• [ZJOI2018]历史


    传送门

    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
    ",ans);
    133     For(ti,1,m) {
    134         int x; LL y;
    135         read(x); read(y);
    136         access(x,y);
    137         printf("%lld
    ",ans);
    138     }
    139     return 0;
    140 }
    View Code
  • 相关阅读:
    打开服务器的文档
    笔记
    centos6.5 编译openssl-1.1.1k
    搭建自己的低代码平台
    防火墙ACL配置自动化
    防火墙ACL配置自动化
    【树莓派】读取新大陆(newland)USB条码扫描器数据
    解决eclipse或sts闪退的办法(转)
    浅谈数据库迁移类项目功能测试的基本思路
    ATM取款机优化需求的用例设计
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8995529.html
Copyright © 2020-2023  润新知