zoukankan      html  css  js  c++  java
  • [ZJOI 2018]历史

    题意:给定一棵树和点的\(Access\)次数,求切换链的最大值。

    考虑修改时实边与虚边的贡献,用\(LCT\)维护此树。

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2000010;
    const int INF = 0x7fffffff;
    #define int long long
    inline int read()
    {
    	int q=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-') f=-1;ch=getchar();
    	}
    	while(isdigit(ch)){
    		q=q*10+ch-'0';ch=getchar();
    	}
    	return q*f;
    }
    int head[maxn];
    int cnt;
    struct edge
    {
    	int nxt;
    	int to;
    }e[maxn<<1];
    inline void add(int u,int v){
    	e[++cnt].to = v;
    	e[cnt].nxt = head[u];
    	head[u] = cnt;
    	return;
    }
    
    int ans;
    
    struct LCT{
    	int ch[maxn][2];
    	int fa[maxn];
    	int stack[maxn];
    	int val[maxn];
    	int sum[maxn];
    	int isum[maxn];
    	inline bool isroot(int x){
    		return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
    	}
    	inline void push_up(int now){
    		sum[now] = val[now] + sum[ch[now][0]]+sum[ch[now][1]]+isum[now];
    	}
    	inline void rotate(int x){
    		int f=fa[x];
    		int ff = fa[f];
    		int y = (ch[f][0] == x);
    		bool flag = isroot(f);
    		fa[x] = ff;
    		fa[f] = x;
    		fa[ch[x][y]] = f;
    		if(!flag) ch[ff][ch[ff][1]==f] = x;
    		ch[f][!y] = ch[x][y];
    		ch[x][y] = f;
    		push_up(f);
    	}
    	inline void splay(int x){
    		while(!isroot(x)){
    			int f = fa[x];
    			if(!isroot(f)){
    				if((ch[fa[f]][0] == f)^(ch[f][0] == x)) rotate(x);
    				else rotate(f);
    			}
    			rotate(x);
    		}
    		push_up(x);
    	}
    	inline void access(int x,int v,int nt){
    		for(;x;nt = x,x = fa[x]){
    			splay(x);
    			int res = sum[ch[x][1]] + val[x] + isum[x];
    			if(ch[x][1]){
    				ans -=((res-sum[ch[x][1]]) << 1);
    			}
    			else if(res + 1 <= val[x] * 2){
    				ans -= 2*(res - val[x]);
    			}
    			else ans -= (res - 1);
    			sum[x] += v;
    			isum[x] += v;
    			res += v;
    			if(res+1 > sum[ch[x][1]]*2){
    				isum[x] += sum[ch[x][1]];
    				ch[x][1] = 0;
    			}
    			if(res + 1<= sum[nt]*2){
    				ch[x][1] = nt;
    				isum[x] -= sum[ch[x][1]];
    			}
    			if(ch[x][1]){
    				ans += 2*(res - sum[ch[x][1]]);
    			}
    			else if(res + 1 <= val[x]*2){
    				ans += 2*(res - val[x]);
    			}
    			else ans += (res - 1);
    		}
    	}
    	inline void update(int x,int f){
    		splay(x);
    		int res = sum[ch[x][1]] + val[x] + isum[x];
    		if(ch[x][1]) ans -= 2*(res - sum[ch[x][1]]);
    		else if(res + 1 <= val[x] * 2){
    			ans -= 2*(res - val[x]);
    		}
    		else ans -= (res - 1);
    		val[x] += f;
    		sum[x] += f;
    		res += f;
    		if(res + 1 > sum[ch[x][1]] * 2){
    			isum[x] += sum[ch[x][1]];
    			ch[x][1] = 0;
    		}
    		if(ch[x][1]){
    			ans += 2*(res - sum[ch[x][1]]);
    		}
    		else if(res + 1 <= val[x] * 2){
    			ans += (res - val[x]) * 2;
    		}
    		else ans += (res - 1);
    		access(fa[x],f,x);
    	}
    	inline void dfs(int x,int f){
    		fa[x] = f;
    		sum[x] = val[x];
    		int maxm = val[x];
    		int i;
    		int tmp = x;
    		for(int i = head[x];i;i=e[i].nxt){
    			int y = e[i].to;
    			if(y == f) continue;
    			dfs(y,x);
    			sum[x] += sum[y];
    			if(sum[y] > maxm){
    				tmp = y;
    				maxm = sum[y];
    			}
    		}
    		ans += min(sum[x]-1,2*(sum[x]-maxm));
    		if(tmp != x && sum[x] + 1 <= maxm * 2) ch[x][1] = tmp;
    		isum[x] = sum[x] - val[x] - sum[ch[x][1]];
    	}
    	inline void ins(){
    		dfs(1,0);
    	}
    }lct;
    
    signed main()
    {
    	int n = read(),m=read();
    	for(int i = 1;i <= n; ++i){
    		lct.val[i] = read();
    	}
    	for(int i = 1;i < n; ++i){
    		int u=read(),v=read();
    		add(u,v);
    		add(v,u);
    	}
    	lct.ins();
    	cout<<ans<<endl;
    	for(int i = 1;i <=m; ++i){
    		int x = read(),v = read();
    		lct.update(x,v);
    		cout<<ans<<endl;	
    	}
    	return 0;
    	
    }
    
  • 相关阅读:
    Steps to Writing Well----Reading Notes
    How to Improve Reading Skills
    Requirement-Driven Linux Shell Programming
    Linux tar command usage
    MVC和MVVM模型
    js中特殊的宏任务
    js 超浓缩 双向绑定
    JavaScript 中的遍历详解
    多段动画整合为一个动画的思路
    Js事件循环(Event Loop)机制
  • 原文地址:https://www.cnblogs.com/akoasm/p/9419221.html
Copyright © 2011-2022 走看看