码迷,mamicode.com
首页 > 其他好文 > 详细

[ZJOI2018]历史

时间:2018-05-05 19:40:18      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:等于   blank   +=   技术分享   条件   using   ++   sof   构造   

传送门

zj的题都好神呀

我怎么什么题都做不来呀

看见这题想起了重组病毒,因为知道了是lct,考虑一下和access有什么不可不说的关系

我一开始没考虑清楚,放弃了这个想法,就GG了...

仔细考虑发现,一个城市崛起等于access操作,fight的次数等于虚实边切换的次数

从我往下没有实边到有实边(前提是我父亲到我是实边,也就是实边往下延伸了一条),或者往下的实边变成另一条实边算一次切换

发现发生这样的切换一定是我的子树中某个点access了,那么每个点的贡献可以分开考虑

每个点记录access的次数v和子树中access的总次数sum

考虑每个点子树中的点的access顺序,如果相邻两个access的点不是来自同一个亲儿子(或者自己)的,就会发生一次fight

如过(t=(v[x]或者x的某个亲儿子的sum)*2)>sum[x]+1,这个点的贡献就为(sum[x]-t)*2,否则贡献为sum[x]-1

yy了一下证明

当存在t*2>sum[x]+1的时候,把t这种点一个空一个的放,其他点插空,然后最后有一些t是相邻的这样是一种最优解

当不存在这样的t时,一种构造出相邻全不相同的方法是,在剩下的点不够插空前,按点数的从多到少拿出某一类点,一个空一个的放,相邻两类之间不空,最后一类要是有剩的肯定可以插到第一类点的空中,然后剩下的类的点插空.

定义每个点的重儿子y满足为sum[y]*2>sum[x]+1,这样会有很多优美的性质

每个点最多有一个重儿子

重儿子在树上形成链

轻重重儿子只会在access的时候改变,和普通access不同的是普通access要改变的现在不一定改变

重链上的点贡献不会改变

每个点向上最多logsum[rt]条轻边,因为轻边存在的条件是sum[fa]+1>sum[x]*2

 

有了这些性质就可以做了,access的时候修改每个会改变的点(log个)的贡献,重链就直接在splay上打上lazytag(打左儿子)

注意没有重儿子也可能我v很大需要按(sum[x]-t)*2计算

技术分享图片
  1 //Achen 
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<cstdio>
  7 #include<cmath>
  8 #include<queue>
  9 #include<set>
 10 #include<map>
 11 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 13 const int N=4e5+7;
 14 typedef long long LL;
 15 typedef double db;
 16 using namespace std;
 17 int n,m,no[N];
 18 LL v[N],sum[N],A[N],ans;
 19 
 20 template<typename T>void read(T &x) {
 21     char ch=getchar(); x=0; T f=1;
 22     while(ch!=-&&(ch<0||ch>9)) ch=getchar();
 23     if(ch==-) f=-1,ch=getchar();
 24     for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f;
 25 }
 26 
 27 int ch[N][2],p[N];
 28 #define lc ch[x][0]
 29 #define rc ch[x][1]
 30 int isroot(int x) {return (ch[p[x]][0]!=x&&ch[p[x]][1]!=x);}
 31 
 32 void rotate(int x) {
 33     int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
 34     if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
 35     ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
 36     ch[x][r]=y; p[y]=x;
 37 }
 38 
 39 LL lz[N];
 40 void down(int x) {
 41     if(!lz[x]) return;
 42     if(lc) sum[lc]+=lz[x],lz[lc]+=lz[x];
 43     if(rc) sum[rc]+=lz[x],lz[rc]+=lz[x];
 44     lz[x]=0;
 45 }
 46 
 47 void splay(int x) {
 48     static int g[N],top=0,tp;
 49     for(tp=x;!isroot(tp);tp=p[tp]) g[++top]=tp;
 50     g[++top]=tp;
 51     while(top) {
 52         down(g[top--]);
 53     }
 54     for(;!isroot(x);rotate(x)) {
 55         int y=p[x],z=p[y];
 56         if(!isroot(y)) 
 57             ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
 58     }
 59 }
 60 
 61 void ADD(int x,LL y) {
 62     if(!x) return;
 63     sum[x]+=y; lz[x]+=y;
 64 }
 65 
 66 int get_min(int x) {
 67     while(lc) {
 68         down(x);
 69         x=lc;
 70     }
 71     return x;
 72 }
 73 
 74 void access(int x,LL V) {
 75     v[x]+=V;
 76     for(int t=0;x;x=p[t=x]) {
 77         splay(x);
 78         sum[x]+=V; ADD(lc,V);
 79         ans-=A[x];
 80         int y=0;
 81         if(rc) y=get_min(rc);
 82         if(y&&sum[y]*2>sum[x]+1) ans+=(A[x]=2LL*(sum[x]-sum[y]));
 83         else rc=0;
 84         if(!rc&&t) {
 85             y=get_min(t);
 86             if(sum[y]*2>sum[x]+1) { ans+=(A[x]=2LL*(sum[x]-sum[y])); rc=t;}
 87         }
 88         if(!rc) {
 89             if(v[x]*2>sum[x]+1) ans+=(A[x]=2LL*(sum[x]-v[x]));
 90             else ans+=(A[x]=sum[x]-1); 
 91         }
 92     }
 93 }
 94 
 95 int ecnt,fir[N],nxt[N<<1],to[N<<1];
 96 void add(int u,int v) {
 97     nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
 98     nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
 99 }
100 
101 void dfs(int x,int fa) {
102     sum[x]=v[x];
103     for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
104         p[to[i]]=x;
105         dfs(to[i],x);
106         sum[x]+=sum[to[i]];
107     }
108     int mson=0;
109     for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
110         if(sum[to[i]]*2>sum[x]+1) {
111             mson=to[i]; break;
112         }
113     }
114     rc=mson; 
115     if(v[x]*2>sum[x]+1) ans+=(A[x]=2LL*(sum[x]-v[x]));
116     else if(mson) ans+=(A[x]=2LL*(sum[x]-sum[mson]));
117     else ans+=(A[x]=sum[x]-1);
118 }
119 
120 //#define DEBUG
121 int main() {
122 #ifdef DEBUG
123     freopen("1.in","r",stdin);
124 #endif
125     read(n); read(m);
126     For(i,1,n) read(v[i]);
127     For(i,1,n-1) {
128         int u,v; read(u); read(v);
129         add(u,v);
130     }
131     dfs(1,0);
132     printf("%lld\n",ans);
133     For(ti,1,m) {
134         int x; LL y;
135         read(x); read(y);
136         access(x,y);
137         printf("%lld\n",ans);
138     }
139     return 0;
140 }
View Code

 

[ZJOI2018]历史

标签:等于   blank   +=   技术分享   条件   using   ++   sof   构造   

原文地址:https://www.cnblogs.com/Achenchen/p/8995529.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!