zoukankan      html  css  js  c++  java
  • 动态点分治

    关于动态点分治

    首先你要先会点分治,然后动态点分治就是把点分治可持久化一下,让其不用再每次询问时都重新做一遍
    具体就是,你考虑做点分的时候,你在每个分治重心上统计它所管辖的所有点的信息,并计算答案。那么每个点的信息只会出现在它上面的分治重心中,所以我们把每层分治重心向上一层的连边,这样每个点的信息只会出现都在它所有的祖先中,然后你维护需要的信息,每次修改就往祖先跳,由于点分治只有(log)层,所以这颗点分树高度只有(log),可以接受。
    维护的信息根据每到题变化,非常灵活。
    例题:

    ZJOI2007捉迷藏

    题意:有一个(n)个点的树,初始都是黑点,现在有两种操作,一种是将一个点反色,另一种是询问树上最远的两个黑点的距离。

    题解:
    求树上最长链我们可以使用点分解决,对于每个分治重心,我们在它所管辖的子树里各找一条到分治重心的最长链,将最长链和次长链拼起来跟新答案。
    现在我们考虑维护一下,对每个点开两个支持删除和取最大值的数据结构,一个存它管辖的所有点到它上一级分治重心的距离(我们称为A),就是一条一条的链。另一个存它所有下一级的分治重心到它的最长链(我们称为B),然后答案就是最长链和次长链的最大值,这个答案也要开个数据结构来维护

    关于这个数据结构,(multiset)可以,但是好像常数巨大,我们使用两个堆来支持就行了,具体来说就是一个存数据,另一个存要删除的,取最大值的时候,如果两个堆队首一样就都弹掉

    关于修改,例如开灯,也就是这个点不能用,对于他自己,把B里面的中的(0)给去掉,防止答案是一条以它为端点的链,对于它每个点分树上的父亲(y),从(y)的A中删去这条链长,再处理一下这次变动对(fa[y])的B的影响即可

    每次改动(B)时,要先将答案数组中他的贡献删掉,改完再加回去。

    根本不能看的代码(下面还有一道例题)

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=1e5+5;
    template<typename T>bool cmax(T &a,T b){return (a<b)?a=b,1:0;}
    template<typename T>bool cmin(T &a,T b){return (a>b)?a=b,1:0;}
    template<typename T>T read()
    {
        T ans=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
        return ans*f;
    }
    template<typename T>void write(T x,char y)
    {
        if(x==0)
        {
            putchar('0'),putchar(y);
            return;
        }
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        static char wr[20];
        int top=0;
        for(;x;x/=10)wr[++top]=x%10+'0';
        while(top)putchar(wr[top--]);
        putchar(y);
    }
    void file()
    {
    #ifndef ONLINE_JUDGE
        freopen("hard.in","r",stdin);
        freopen("hard.out","w",stdout);
    #endif
    }
    int n;
    vector<int>E[N];
    #define pb push_back
    void input()
    
    {
        int x,y;
        n=read<int>();
        For(i,2,n)
        {
            x=read<int>(),y=read<int>();
            E[x].pb(y),E[y].pb(x);
        }
    }
    typedef priority_queue<int> Q;
    struct PQ
    {
        Q q,del;
        void push(int x){q.push(x);}
        void erase(int x){del.push(x);}
        int top()
        {
            while(!del.empty()&&del.top()==q.top())
                {del.pop(),q.pop();}
            return q.top();
        }
        void pop()
        {
            while(!del.empty()&&del.top()==q.top())
            {del.pop(),q.pop();}
            q.pop();
        }
        int sec()
        {
            int y=top(),res;
            pop();
            res=y+top();
            push(y);
            return res;
        }
        int size(){return q.size()-del.size();}
    }A[N],B[N],ans;
    //multiset<int>A[N],B[N],ans;
    const int inf=0x3f3f3f3f;
    int fa[N],size[N],rt,Min,sum;
    bool ban[N];
    void get_root(int u,int pre)
    {
        int v,Max=0;
        size[u]=1;
        For(i,0,E[u].size()-1)
        {
            v=E[u][i];
            if(v==pre||ban[v])continue;
            get_root(v,u);
            size[u]+=size[v];
            cmax(Max,size[v]);
        }
        cmax(Max,sum-size[u]);
        if(cmin(Min,Max))rt=u;
    }
    void get_dep(int u,int pre,int dis)
    {
        //cout<<u<<' '<<dis<<' '<<rt<<' '<<fa[rt]<<endl;
    //	cout<<"A"<<' '<<rt<<' '<<dis<<' '<<u<<endl;
        int v;
        A[rt].push(dis);
        For(i,0,E[u].size()-1)
        {
            v=E[u][i];
            if(v==pre||ban[v])continue;
            get_dep(v,u,dis+1);
        }
    }
    void insert(PQ &s)
    {
        if(s.size()>1)
        {
    //		cout<<"C"<<' '<<s.sec()<<endl;
            ans.push(s.sec());
        }
    }
    void erase(PQ s)
    {
        if(s.size()>1)
        {
    //		cout<<"D"<<' '<<s.sec()<<endl;
            ans.erase(s.sec());
        }
    }
    void solve(int u)
    {
        int v;
        ban[u]=1;
        //cerr<<u<<endl;
        B[u].push(0);
        For(i,0,E[u].size()-1)
        {
            v=E[u][i];
            if(ban[v])continue;
            //cerr<<u<<' '<<v<<endl;;
    
            sum=Min=size[v];
            get_root(v,u);
    
            fa[rt]=u;
            get_dep(v,u,1);
        //	cout<<"B"<<' '<<u<<' '<<A[rt].top()<<endl;
            //cout<<u<<' '<<rt<<endl;
            //B[u].insert(fir(A[rt]));
            //cout<<fir(A[rt])<<endl;
            //B[u].insert(fir(A[u]));
            //int res=fir(A[rt]);
            //cerr<<u<<' '<<res<<endl;
            B[u].push(A[rt].top());
            //cerr<<u<<' '<<res<<endl;
            solve(rt);
        }
        //cerr<<endl;
        insert(B[u]);
    }
    int dep[N],st[N][21],Log[N];
    void dfs(int u,int pre)
    {
        int v;
        dep[u]=dep[pre]+1;
        st[u][0]=pre;
    
        For(i,1,Log[dep[u]])st[u][i]=st[st[u][i-1]][i-1];
        For(i,0,E[u].size()-1)
        {
            v=E[u][i];
            if(v==pre)continue;
            dfs(v,u);
        }
    }
    void init()
    {
        For(i,1,n)Log[i]=Log[i>>1]+1;
        dfs(1,0);
        rt=0;Min=sum=n;
        get_root(1,0);
        get_dep(1,0,1);
        solve(rt);
    //	For(i,1,n)cout<<fa[i]<<' ';
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        int s=dep[x]-dep[y];
        Fordown(i,Log[s],0)
            if((s>>i)&1)x=st[x][i];
        if(x==y)return x;
        s=dep[x];
        Fordown(i,Log[s],0)
        {
            if(st[x][i]^st[y][i])
                x=st[x][i],y=st[y][i];
        }
        return st[x][0];
    }
    int Dis(int x,int y){return dep[x]+dep[y]-dep[LCA(x,y)]*2;}
    char opt[20];
    int m,cl[N],cnt;
    
    void on(int x)
    {
    //	cerr<<B[x].size()<<endl;
        int t1,t2;
        t1=B[x].size()>1?B[x].sec():-1;
        //erase(B[x]);
        //cout<<endl;
        //cout<<x<<endl;
        //for(it=ans.rbegin();it!=ans.rend();++it)cout<<*it<<' ';
        //cout<<endl<<endl;;
        B[x].erase(0);
        t2=B[x].size()>1?B[x].sec():-1;
        if(t1!=t2)
        {
            if(t1!=-1)ans.erase(t1);
            if(t2!=-1)ans.push(t2);
        }
        //insert(B[x]);
        //B[x].erase(B[x].lower_bound(0));
        //cerr<<x<<endl<<endl;;
        for(int y=x;fa[y];y=fa[y])
        {
        //	cout<<fa[y]<<' '<<B[fa[y]].size()<<endl;
            t1=B[fa[y]].size()>1?B[fa[y]].sec():-1;
            //erase(B[fa[y]]);
            if(A[y].size())B[fa[y]].erase(A[y].top());
            A[y].erase(Dis(x,fa[y]));
        //	cout<<"Dis"<<' '<<Dis(x,fa[y])<<endl;
            if(A[y].size())B[fa[y]].push(A[y].top());
            //insert(B[fa[y]]);
            t2=B[fa[y]].size()>1?B[fa[y]].sec():-1;	
            if(t1!=t2)
            {
                if(t1!=-1)ans.erase(t1);
                if(t2!=-1)ans.push(t2);
            }
        }
    }
    void off(int x)
    {
        int t1,t2;
    
        t1=B[x].size()>1?B[x].sec():-1;	
        //erase(B[x]);
        B[x].push(0);
        //insert(B[x]);
        t2=B[x].size()>1?B[x].sec():-1;	
        if(t1!=t2)
        {
            if(t1!=-1)ans.erase(t1);
            if(t2!=-1)ans.push(t2);
        }
        for(int y=x;fa[y];y=fa[y])
        {
            //erase(B[fa[y]]);
            t1=B[fa[y]].size()>1?B[fa[y]].sec():-1;	
            if(A[y].size())B[fa[y]].erase(A[y].top());
            A[y].push(Dis(x,fa[y]));
        //	cout<<"Dis"<<' '<<Dis(x,fa[y])<<endl;
            if(A[y].size())B[fa[y]].push(A[y].top());
            //insert(B[fa[y]]);
            t2=B[fa[y]].size()>1?B[fa[y]].sec():-1;	
            if(t1!=t2)
            {
                if(t1!=-1)ans.erase(t1);
                if(t2!=-1)ans.push(t2);
            }
        }
    }
    void work()
    {
        //For(i,1,n)cout<<fa[i]<<' ';
        //write(fir(ans),'
    ');
        int x;
        cnt=n;
        m=read<int>();
        For(i,1,m)
        {
            scanf("%s",opt);
            if(opt[0]=='C')
            {
                x=read<int>();
                if(!cl[x])
                {
                    cl[x]=1;
                    cnt--;
                    on(x);
                }
                else
                {
                    cl[x]=0;
                    cnt++;
                    off(x);
                }
            }
            else
            {
                if(cnt<=1)write(cnt-1,'
    ');
                else write(ans.top(),'
    ');
            }
        //	cout<<endl;
        }
    }
    int main()
    {
        file();
        input();
        init();
        work();
        return 0;
    }
    
    

    BZOJ3730

    题意:一颗(n)个点的树,每个点有点权,要求支持修改一个点权和查询距离某个点距离不超过(k)的点的点权和

    题解:

    每个点开两个树状数组,分别维护距它不超过多少的点权之和,和它子树中距离它父亲不超过多少的点权之和

    这样在询问时对于每一个分治重心(y),贡献就是不超过(k-dis(x,y))的点权和减去不超过(dis(x,fa[y]))的点权和,减去的这部分会在他的父亲被算回来。

    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=1e5+5;
    template<typename T>bool cmax(T &a,T b){return (a<b)?a=b,1:0;}
    template<typename T>bool cmin(T &a,T b){return (a>b)?a=b,1:0;}
    template<typename T>T read()
    {
    	T ans=0,f=1;
    	char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
    	return ans*f;
    }
    template<typename T>void write(T x,char y)
    {
    	if(x==0)
    	{
    		putchar('0'),putchar(y);
    		return;
    	}
    	if(x<0)
    	{
    		putchar('-');
    		x=-x;
    	}
    	static char wr[20];
    	int top=0;
    	for(;x;x/=10)wr[++top]=x%10+'0';
    	while(top)putchar(wr[top--]);
    	putchar(y);
    }
    void file()
    {
    #ifndef ONLINE_JUDGE
    	freopen("3730.in","r",stdin);
    	freopen("3730.out","w",stdout);
    #endif
    }
    int n,m;
    int val[N];
    vector<int>E[N];
    #define pb push_back
    void input()
    {
    	int x,y;
    	n=read<int>(),m=read<int>();
    	For(i,1,n)val[i]=read<int>();
    	For(i,2,n)
    	{
    		x=read<int>(),y=read<int>();
    		E[x].pb(y),E[y].pb(x);
    	}
    }
    bool ban[N];
    int rt,Min,sum,size[N];
    void get_root(int u,int pre)
    {
    	int v,Max=0;
    	size[u]=1;
    	For(i,0,E[u].size()-1)
    	{
    		v=E[u][i];
    		if(v==pre||ban[v])continue;
    		get_root(v,u);
    		size[u]+=size[v];
    		cmax(Max,size[v]);
    	}
    	cmax(Max,sum-size[u]);
    	if(cmin(Min,Max))rt=u;
    }
    int fa[N][21],cnt[N],dis[N][21];
    vector<int>s1[N],s2[N];
    void get_dep(int u,int pre,int G,int Dis)
    {
    	int v;
    	For(i,0,E[u].size()-1)
    	{
    		v=E[u][i];
    		if(v==pre||ban[v])continue;
    		++cnt[v];
    		fa[v][cnt[v]]=G,dis[v][cnt[v]]=Dis+1;
    		get_dep(v,u,G,Dis+1);
    	}
    }
    int sz;
    void solve(int u)
    {
    	//cerr<<u<<' '<<sum<<endl;
    	s1[u].resize(sum+1),s2[u].resize(sum+1);
    //	cout<<s1[u].size()-1<<endl;
    	int v,all=sum;
    	ban[u]=1;
    	get_dep(u,u,u,0);
    	For(i,0,E[u].size()-1)
    	{
    		v=E[u][i];
    		if(ban[v])continue;
    	//	cerr<<u<<' '<<v<<endl;
    		//get_dep(v,u,u,1i);
    		//cerr<<size[v]<<' '<<size[u]<<' '<<sum<<endl;
    		sum=Min=(size[v]>size[u]?all-size[u]:size[v]);
    		get_root(v,u);
    		//cout<<rt<<' '<<sum<<' '<<Min<<endl;
    		solve(rt);
    	}
    }
    void init()
    {
    	sum=Min=n;
    	get_root(1,0);
    	solve(rt);
    }
    void add(vector<int> &s,int x,int v)
    {
    	//cerr<<x<<' '<<limte<<endl;
    	int limte=s.size()-1;
    	for(;x&&x<=limte;x+=x&-x)s[x]+=v;
    }
    int cal(vector<int> &s,int x)
    {
    	cmin(x,(int)s.size()-1);
    	int res=0;
    	for(;x;x-=x&-x)res+=s[x];
    	return res;
    }
    void insert(int x,int v)
    {	
       // if(!x||x>n)return;
    //	cerr<<dis[x][cnt[x]]<<' '<<x<<' '<<fa[x][cnt[x]]<<endl;
        if(!x||x>n)return;
    	add(s2[x],dis[x][cnt[x]],v);
    //	for(int j=dis[x][cnt[x]];j&&j<s2[x].size();j+=j&-j)s2[x][j]+=v;
    	Fordown(i,cnt[x],1)
    	{
    	//	cerr<<fa[x][i]<<' '<<s1[fa[x][i]].size()-1<<' '<<dis[x][i]<<' '<<dis[x][i-1]<<endl;
    		add(s1[fa[x][i]],dis[x][i],v);
    		add(s2[fa[x][i]],dis[x][i-1],v);
    		
    //	for(int j=dis[x][i];j&&j<s1[fa[x][i]].size();j+=j&-j)s1[fa[x][i]][j]+=v;
    //	for(int j=dis[x][i-1];j&&j<s1[fa[x][i]].size();j+=j&-j)s2[fa[x][i]][j]+=v;
    	}
    }
    int query(int x,int k)
    {
     //   if(!x||x>n)return 0;
    	int res=cal(s1[x],k)+val[x];
    //	cerr<<res<<endl;
    	Fordown(i,cnt[x],1)if(dis[x][i]<=k)
    	{
    		res+=val[fa[x][i]]+cal(s1[fa[x][i]],k-dis[x][i])-cal(s2[fa[x][i+1]],k-dis[x][i]);
    //	cerr<<fa[x][i]<<' '<<res<<endl;
    	}
    	return res;
    }
    int lans;
    void work()
    {
    //	For(i,1,n)cout<<fa[i][cnt[i]]<<' ';puts("");
    	int opt,x,y;
    	//For(i,1,n)cout<<i<<' '<<(int)s1[i].size()<<endl;
    	//For(i,1,n)For(j,1,cnt[i])cout<<fa[i][j]<<' '<<dis[i][j]<<' '<<(j==cnt[i]?'
    ':' ');
    	For(i,1,n)insert(i,val[i]);
    	For(i,1,n)fa[i][cnt[i]+1]=i;
    	while(m--)
    	{
    		opt=read<int>(),x=read<int>()^lans,y=read<int>()^lans;
    		if(opt==0)lans=query(x,y),write(lans,'
    ');
    		else insert(x,y-val[x]),val[x]=y;
    	}
    }
    int main()
    {
    	file();
    	input();
    	init();
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    基因疗法 中国科学家利用基因疗法成功逆转1型糖尿病进程
    麻省理工比特币
    数据处理包dplyr的函数
    资源革命
    翻译文章第六章4-7
    kaggle Titanic心得
    Javascript高级编程学习笔记(56)—— DOM2和DOM3(8)低版本IE范围
    Javascript高级编程学习笔记(55)—— DOM2和DOM3(7)操作范围
    Javascript高级编程学习笔记(54)—— DOM2和DOM3(6)范围选择
    Javascript高级编程学习笔记(53)—— DOM2和DOM3(5)遍历
  • 原文地址:https://www.cnblogs.com/dengyixuan/p/9221942.html
Copyright © 2011-2022 走看看