• bzoj3589 动态树


     题意:给你一棵树,要求你维护两个操作.

     0:某子树的所有节点权值加上一个数.

     1:求某些链并集的权值和.

     对于第一个操作,大力树链剖分加线段树.

     对于第二个操作,考虑到链的数量很少,可以容斥.

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iomanip>
    using namespace std;
    #define LL long long
    #define up(i,j,n) for(int i=j;i<=n;i++)
    #define pii pair<int,int>
    #define db double
    #define eps 1e-4
    #define FILE "dealing"
    int read(){
    	int x=0,f=1,ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();}
    	return x*f;
    }
    const LL maxn=1000000,inf=1000000000000000LL,limit=20000;
    bool cmin(int& a,int b){return a>b?a=b,true:false;}
    bool cmax(int& a,int b){return a<b?a=b,true:false;}
    int n,m;
    struct node{
    	int y,next;
    }e[maxn];
    int len=0,linkk[maxn],top[maxn],fa[maxn],dep[maxn],pre[maxn],low[maxn];
    void insert(int x,int y){
    	e[++len].y=y;
    	e[len].next=linkk[x];
    	linkk[x]=len;
    }
    void init(){
    	n=read();
    	up(i,1,n-1){
    		int x=read(),y=read();
    		insert(x,y);
    		insert(y,x);
    	}
    }
    namespace treepou{
    	int dfs_clock=0,siz[maxn],son[maxn];
    	void dfs1(int x){
    		siz[x]=1;
    		for(int i=linkk[x];i;i=e[i].next){
    			if(e[i].y==fa[x])continue;
    			fa[e[i].y]=x;
    			dep[e[i].y]=dep[x]+1;
    			dfs1(e[i].y);
    			siz[x]+=siz[e[i].y];
    			if(siz[e[i].y]>siz[son[x]])son[x]=e[i].y;
    		}
    	}
    	void dfs2(int x){
    		pre[x]=++dfs_clock;
    		if(son[x]){
    			top[son[x]]=top[x];
    			dfs2(son[x]);
    		}
    		for(int i=linkk[x];i;i=e[i].next){
    			if(e[i].y==son[x]||e[i].y==fa[x])continue;
    			top[e[i].y]=e[i].y;
    			dfs2(e[i].y);
    		}
    		low[x]=dfs_clock;
    	}
    	void solve(){
    		dfs1(1);
    		top[1]=1;
    		dfs2(1);
    	}
    };
    namespace SegTree{
    	int del[maxn],siz[maxn],sum[maxn],L,R,key,id[maxn];
    	int Add(int x,int d){
    		del[x]+=d;
    		sum[x]+=siz[x]*d;
    	}
    	void updata(int x){
    		sum[x]=sum[x<<1]+sum[x<<1|1];
    	}
    	void pushdown(int x){
    		if(del[x]){
    			Add(x<<1,del[x]);
    			Add(x<<1|1,del[x]);
    			del[x]=0;
    		}
    	}
    	void change(int o,int l,int r){
    		if(l>R||r<L)return;
    		if(l>=L&&r<=R){Add(o,key);return;}
    		int mid=(l+r)>>1;
    		pushdown(o);
    		change(o<<1,l,mid);
    		change(o<<1|1,mid+1,r);
    		updata(o);
    	}
    	void Change(int x,int y,int Del){
    		L=x,R=y,key=Del;
    		change(1,1,n);
    	}
    	int query(int l,int r,int o){
    		if(l>R||r<L)return 0;
    		if(l>=L&&r<=R)return sum[o];
    		int mid=(l+r)>>1;
    		pushdown(o);
    		return query(l,mid,o<<1)+query(mid+1,r,o<<1|1);
    	}
    	int Query(int x,int y){
    		if(x>y)swap(x,y);
    		L=x,R=y;
    		return query(1,n,1);
    	}
    	void build(int l,int r,int o){
    		if(l==r){
    			siz[o]=1;
    			sum[o]=0;
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(l,mid,o<<1);
    		build(mid+1,r,o<<1|1);
    		siz[o]=siz[o<<1]+siz[o<<1|1];
    	}
    	void Build(){
    		up(i,1,n)id[pre[i]]=i;
    		build(1,n,1);
    	}
    }
    namespace solve{
    	pii getlian(int x,int y){
    		int f1,f2;
    		int sum=0;
    		while(true){
    			if(dep[x]>dep[y])swap(x,y);
    			f1=top[x],f2=top[y];
    			if(f1==f2){
    				sum+=SegTree::Query(pre[x],pre[y]);
    				return make_pair(x,sum);
    			}
    			if(dep[f1]>dep[f2])swap(x,y),swap(f1,f2);
    			sum+=SegTree::Query(pre[f2],pre[y]);
    			y=fa[f2];
    		}
    	}
    	int getlca(int x,int y){
    		int f1,f2;
    		while(true){
    			if(dep[x]>dep[y])swap(x,y);
    			f1=top[x],f2=top[y];
    			if(f1==f2)return x;
    			if(dep[f1]>dep[f2])swap(x,y),swap(f1,f2);
    			y=fa[f2];
    		}
    	}
    	pii t[maxn];
    	int query(){
    		int m=read();
    		up(i,1,m){
    			t[i].first=read(),t[i].second=read();
    			if(dep[t[i].first]>dep[t[i].second])swap(t[i].first,t[i].second);
    		}
    		pii y=make_pair(0,0);
    		int ans=0;
    		for(int i=1;i<(1<<m);i++){
    			int g=-1,flag=0;
    			up(j,1,m){
    				if(i&(1<<j-1))g*=-1;
    				else continue;
    				if(!flag)y=t[j],flag=1;
    				else {
    					int w=getlca(y.second,t[j].second);
    					
    					if(dep[w]<dep[y.first]||dep[w]<dep[t[j].first]){
    						y=make_pair(0,0);
    						break;
    					}
    					else {
    						if(dep[y.first]<dep[t[j].first])y.first=t[j].first;
    						y.second=w;
    					}
    				}
    			}
    			//printf("%d %d %d
    ",g,y.first,y.second);
    			if(y.first)ans+=g*getlian(y.first,y.second).second;
    		}
    		return ans;
    	}
    };
    
    int main(){
    	freopen(FILE".in","r",stdin);
    	freopen(FILE".out","w",stdout);
    	init();
    	treepou::solve();//树剖 返回top,dep,fa
    	SegTree::Build();//prepare SegTree 
    	int m=read();
    	while(m--){
    		int ch=read();
    		if(ch==0){
    			int x=read(),del=read();
    			SegTree::Change(pre[x],low[x],del);
    		}
    		else printf("%d
    ",solve::query()&((1<<31)-1));
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    解决无线打印机休眠后掉线无法进行局域网打印的问题
    快速为某个目录的verilog文件生成filelist
    使用Visual Studio的Spy++查找弹窗广告进程
    【转载】verilog语法之generate语句的基本认识
    补码(为什么按位取反再加一):告诉你一个其实很简单的问题
    【转载】EDID的简介和解析
    win32diskimager 谨慎使用
    UXE的一些使用归纳
    如何在win8或win10系统里添加inf驱动程序
    STM32 USB HID
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6492672.html
Copyright © 2020-2023  润新知