P3313 [SDOI2014]旅行(计时器)

本文介绍了一种结合树链剖分和动态开点线段树的数据结构算法,用于解决涉及树形结构的复杂查询问题。通过树剖分预处理,将树转化为线段树,实现高效的区间更新和查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

树链剖分+动态开点的线段树

   树剖好以后每个宗教建一棵线段树,把初始状态每个城市插入树中。

   查询时边求LCA边在线段树中查询。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<Windows.h>
using namespace std;
int wi[100010],ci[100010],to[200010],nex[200010],head[100010];
int d[100010],son[100010],s[100010],fa[100010],rt[100010],cnt=1;
int top[100010],id[100010],rk[100010],n,qx,qy,qc;
struct node
{
    int sum,m,l,r;
}tree[10000000];
void dfs1(int now,int deep)
{
    d[now]=deep;
    s[now]=1;
    for(int i=head[now];i>0;i=nex[i])
    {
        if(to[i]==fa[now])
            continue;
        fa[to[i]]=now;
        dfs1(to[i],deep+1);
        s[now]+=s[to[i]];
        if(s[to[i]]>s[son[now]])
            son[now]=to[i];
    }
}
void dfs2(int now,int t)
{
    top[now]=t;
    id[now]=++id[0];
    rk[id[now]]=now;
    if(!son[now])
        return;
    dfs2(son[now],t);
    for(int i=head[now];i>0;i=nex[i])
    {
        if(to[i]==son[now]||to[i]==fa[now])
            continue;
        dfs2(to[i],to[i]);
    }
}
void build(int l,int r,int &rt,int x,int w)
{
    if(!rt)
    rt=cnt++;
    if(l==r)
    {
        tree[rt].sum+=w;
        tree[rt].m=max(tree[rt].m,w);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
        build(l,mid,tree[rt].l,x,w);
    else
        build(mid+1,r,tree[rt].r,x,w);
    tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum;
    tree[rt].m=max(tree[tree[rt].l].m,tree[tree[rt].r].m);
}
void change1(int l,int r,int &rt,int x)
{
   /* if(!rt)
    rt=cnt++;*/
    if(l==r)
    {
        tree[rt].sum=0;
        tree[rt].m=0;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
        change1(l,mid,tree[rt].l,x);
    else
        change1(mid+1,r,tree[rt].r,x);
    tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum;
    tree[rt].m=max(tree[tree[rt].l].m,tree[tree[rt].r].m);
}
void change2(int l,int r,int &rt,int x,int w)
{
    /*if(!rt)
    rt=cnt++;*/
    if(l==r)
    {
        tree[rt].sum=w;
        tree[rt].m=w;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
        change2(l,mid,tree[rt].l,x,w);
    else
        change2(mid+1,r,tree[rt].r,x,w);
    tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum;
    tree[rt].m=max(tree[tree[rt].l].m,tree[tree[rt].r].m);
}
int qs(int l,int r,int rt)
{
    if(qx<=l&&r<=qy)
    return tree[rt].sum;
    int mid=(l+r)>>1,ans=0;
    if(qx<=mid)
        ans+=qs(l,mid,tree[rt].l);
    if(qy>mid)
        ans+=qs(mid+1,r,tree[rt].r);
    return ans;
}
int qm(int l,int r,int rt)
{
    if(qx<=l&&r<=qy)
        return tree[rt].m;
    int mid=(l+r)>>1,ans=0;
    if(qx<=mid)
        ans=max(ans,qm(l,mid,tree[rt].l));
    if(qy>mid)
        ans=max(ans,qm(mid+1,r,tree[rt].r));
    return ans;
}
int lca(int x,int y,int h)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(d[top[x]]>d[top[y]])
        {
            qx=id[top[x]];qy=id[x];
            if(h)
            ans+=qs(1,n,rt[qc]);
            else
            ans=max(ans,qm(1,n,rt[qc]));
            x=fa[top[x]];
        }
        else
        {
            qx=id[top[y]];qy=id[y];
            if(h)
            ans+=qs(1,n,rt[qc]);
            else
            ans=max(ans,qm(1,n,rt[qc]));
            y=fa[top[y]];
        }
    }
    if(d[x]>d[y])swap(x,y);
    qx=id[x];qy=id[y];
    if(h)
    ans+=qs(1,n,rt[qc]);
    else
    ans=max(ans,qm(1,n,rt[qc]));
    return ans;
}
inline int read()
{
    char c;
    int re=0;
    c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        re=re*10+c-'0';
        c=getchar();
    }
    return re;
}
int main()
{
    //freopen("1.txt","r",stdin);
   // freopen("2.txt","w",stdout);
    //DWORD startTime = GetTickCount();
    int q,con=1;
    n=read();q=read();
    for(int i=1;i<=n;++i)
    {wi[i]=read();ci[i]=read();}
    for(int i=1;i<n;++i)
    {
        int a,b;
        a=read();b=read();
        to[con]=b;nex[con]=head[a];head[a]=con++;
        to[con]=a;nex[con]=head[b];head[b]=con++;
    }
    fa[1]=1;
    dfs1(1,1);
    dfs2(1,1);
    for(int i=1;i<=n;++i)
    build(1,n,rt[ci[i]],id[i],wi[i]);
//    build(1,n,1);
   // int times=1;
    for(int i=1;i<=q;++i)
    {
        int x,y;
        char c,q;
        c=getchar();
        while(c!='C'&&c!='Q')
            c=getchar();
        q=getchar();
        x=read();y=read();
        if(c=='C')
        {
            if(q=='C')
            {
            change1(1,n,rt[ci[x]],id[x]);
            ci[x]=y;
            build(1,n,rt[ci[x]],id[x],wi[x]);
            }
            else
            {
            wi[x]=y;
            change2(1,n,rt[ci[x]],id[x],y);
            }
        }
        else
        {
            qc=ci[x];
            if(q=='S')
            printf("%d\n",lca(x,y,1));
            else
            printf("%d\n",lca(x,y,0));
         /*   if(times==479)
            {
                cout<<c<<q<<x<<' '<<y<<endl;
                return 0;
            }
            times++;*/
        }
    }
        /*DWORD endTime = GetTickCount();//¼ÆÊ±½áÊø
        cout << "The run time is:" << endTime - startTime << "ms" << endl;*/
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值