zoukankan      html  css  js  c++  java
  • BZOJ 3091 城市旅行 (LCT)

    题目大意:

     

    很显然是一个$LCT$题= =

    操作1,2都是$LCT$基本操作,操作3打个标记即可

    重点就是操作4该如何在$LCT$里维护,我们先不管期望的问题,只需要把总和$/(sum*(sum+1)/2)$即可

    我们把链拎出来,摊平

    每个节点的答案,就是它(左侧节点数+1)*(右侧节点数+1)*它的权值

    我们在用$splay$维护动态链时,$splay$树中,我们每个节点为根的子树都能表示一条链

    一个节点$x$连接了左右子节点$ls,rs$,那么,$x$子树表示的链,相当于把$ls$的链,$x$节点,$rs$的链的接在了一起

    我们需要把它们的信息进行合并

    发现这其实是一个卷积的形式

    $splay$中,每个节点维护,子树中节点数量$sz$,子树中节点权值总和$sum$,以及$lx,rx$表示它子树中所有节点的权值*(这些节点左/右侧节点数量+1),最后一个答案数组$tx$

    这几个数组在$pushup$里很好处理,建议自己推式子

    关键是在$update$后,下推标记时该如何处理。我们必须保证下推标记后,子节点的$lx,rx,tx$数组能$O(1)$更新

    设增加的权值是$tag$

    显然$lx,rx$都会增加$tag*sz_{x}*(sz_{x}+1)/2$,把链摊开,$tag$对每个节点的贡献是一个等差数列

    $tag$对答案$tx$的更新值是$sum icdot(sz-i+1)$ 其中$i$表示它在摊开链中的位置

    展开,再用$1~n$平方和公式,可得$tag$对答案的贡献是$tag*sz*(sz+1)*(sz+2)/6$

    注意!$revers$操作需要把$lx$和$rx$交换!

    另外由于操作中可能有一部分边不能连,每次都$findroot$会消耗大量时间

    所以每次$findroot$后,把根转上去能大幅优化常数

    还有,$namespace$跑得是真的慢..$struct$就飞快

      1 #include <queue>
      2 #include <vector>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 #define N1 50100
      7 #define M1 2010
      8 #define S1 (N1<<1)
      9 #define T1 (N1<<2)
     10 #define ll long long
     11 #define uint unsigned int
     12 #define rint register int 
     13 #define ull unsigned long long
     14 #define dd double
     15 #define il inline 
     16 #define inf 1000000000
     17 using namespace std;
     18 
     19 int gint()
     20 {
     21     int ret=0,fh=1;char c=getchar();
     22     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     23     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     24     return ret*fh;
     25 }
     26 int n,m,T,type;
     27 int tot;
     28 struct LCT{
     29 int ch[N1][2],fa[N1],rev[N1],val[N1],tag[N1];
     30 ll lx[N1],rx[N1],tx[N1],sum[N1],sz[N1];
     31 inline int idf(int x){return ch[fa[x]][0]==x?0:1;}
     32 inline int isroot(int x){return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1;}
     33 void revers(int x)
     34 {
     35     swap(ch[x][0],ch[x][1]);
     36     swap(lx[ch[x][0]],rx[ch[x][0]]);
     37     swap(lx[ch[x][1]],rx[ch[x][1]]);
     38     rev[x]^=1;
     39 }
     40 void pushup(int x)
     41 {
     42     int ls=ch[x][0],rs=ch[x][1];
     43     sz[x]=sz[ls]+sz[rs]+1;
     44     sum[x]=sum[ls]+sum[rs]+val[x];
     45     lx[x]=lx[ls]+lx[rs]+1ll*(sum[ls]+val[x])*(sz[rs]+1);
     46     rx[x]=rx[ls]+rx[rs]+1ll*(sum[rs]+val[x])*(sz[ls]+1);
     47     tx[x]=tx[ls]+tx[rs]+1ll*rx[ls]*(sz[rs]+1)+1ll*lx[rs]*(sz[ls]+1)+1ll*val[x]*(sz[ls]+1)*(sz[rs]+1);
     48 }
     49 void pushdown(int x)
     50 {
     51     if(rev[x])
     52     {
     53         if(ch[x][0]) revers(ch[x][0]);
     54         if(ch[x][1]) revers(ch[x][1]);
     55         rev[x]^=1;
     56     }
     57     if(tag[x])
     58     {
     59         int ls=ch[x][0],rs=ch[x][1]; ll w=tag[x];
     60         if(ls)
     61         {
     62             tag[ls]+=w,val[ls]+=w,sum[ls]+=1ll*sz[ls]*w;
     63             lx[ls]+=1ll*w*(sz[ls]+1)*sz[ls]/2;
     64             rx[ls]+=1ll*w*(sz[ls]+1)*sz[ls]/2;
     65             tx[ls]+=1ll*sz[ls]*(sz[ls]+1)*(sz[ls]+2)/6*w;
     66         }
     67         if(rs)
     68         {
     69             tag[rs]+=w,val[rs]+=w,sum[rs]+=1ll*sz[rs]*w;
     70             lx[rs]+=1ll*(sz[rs]+1)*sz[rs]/2*w;
     71             rx[rs]+=1ll*(sz[rs]+1)*sz[rs]/2*w;
     72             tx[rs]+=1ll*sz[rs]*(sz[rs]+1)*(sz[rs]+2)/6*w;
     73         }
     74         tag[x]=0;
     75     }
     76 }
     77 void rot(int x)
     78 {
     79     int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
     80     if(!isroot(y)) ch[ff][py]=x; fa[x]=ff;
     81     fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1];
     82     ch[x][px^1]=y,fa[y]=x;
     83     pushup(y),pushup(x);
     84 }
     85 int stk[N1],tp;
     86 void splay(int x)
     87 {
     88     int y=x; stk[++tp]=x;
     89     while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];}
     90     while(tp){pushdown(stk[tp--]);}
     91     while(!isroot(x))
     92     {
     93         y=fa[x];
     94         if(isroot(y)) rot(x);
     95         else if(idf(y)==idf(x)) rot(y),rot(x);
     96         else rot(x),rot(x);
     97     }
     98 }
     99 void access(int x)
    100 {
    101     for(int y=0;x;y=x,x=fa[x]) 
    102         splay(x),ch[x][1]=y,pushup(x);
    103 }
    104 void mkroot(int x)
    105 {
    106     access(x),splay(x),revers(x);
    107     swap(lx[x],rx[x]);
    108 }
    109 int fdroot(int x)
    110 {
    111     access(x),splay(x); 
    112     while(ch[x][0]) x=ch[x][0],pushdown(x);
    113     splay(x); return x;
    114 }
    115 void split(int x,int y){mkroot(x),access(y),splay(y);}
    116 void link(int x,int y)
    117 {
    118     mkroot(x);
    119     if(fdroot(y)!=x) fa[x]=y;
    120 }
    121 void cut(int x,int y)
    122 {
    123     split(x,y);
    124     if(!ch[x][1]&&fa[x]==y&&ch[y][0]==x) 
    125         ch[y][0]=fa[x]=0,pushup(y);
    126 }
    127 ll query(int x,int y)
    128 {
    129     split(x,y);
    130     if(fdroot(y)!=x) return -1; 
    131     return tx[x];
    132 }
    133 void update(int x,int y,int w)
    134 {
    135     split(x,y);
    136     if(fdroot(y)!=x) return;
    137     tag[x]+=w,val[x]+=w,sum[x]+=1ll*w*sz[x];
    138     lx[x]+=1ll*w*(sz[x]+1)*sz[x]/2;
    139     rx[x]+=1ll*w*(sz[x]+1)*sz[x]/2;
    140     tx[x]+=1ll*sz[x]*(sz[x]+1)*(sz[x]+2)/6*w;
    141 }
    142 void init(){for(int i=1;i<=n;i++) sz[i]=1,pushup(i);}
    143 }lct;
    144 ll gcd(ll x,ll y){if(!y) return x; return gcd(y,x%y);}
    145 
    146 int main()
    147 {
    148     int i,j,x,y,w,fl;ll ans,g,nn;
    149     scanf("%d%d",&n,&m);
    150     for(i=1;i<=n;i++) lct.val[i]=gint();
    151     lct.init();
    152     for(j=1;j<n;j++) x=gint(), y=gint(), lct.link(x,y);
    153     for(j=1;j<=m;j++)    
    154     {
    155         fl=gint(); x=gint(); y=gint();
    156         if(fl==1) lct.cut(x,y);
    157         if(fl==2) lct.link(x,y);
    158         if(fl==3) w=gint(),lct.update(x,y,w);
    159         if(fl==4)
    160         {
    161             ans=lct.query(x,y);
    162             if(ans==-1) {puts("-1");continue;}
    163             nn=1ll*(lct.sz[x])*(lct.sz[x]+1)/2;
    164             g=gcd(ans,nn);
    165             printf("%lld/%lld
    ",ans/g,nn/g);
    166         }
    167     }
    168     return 0;
    169 }
  • 相关阅读:
    Miller-Rabin素性测试
    ###Canny边缘检测算子
    ###SIFT特征
    建立一个免费的网站
    ###C中的extern-static-const关键词
    ###Git使用问题
    ###Fedora下安装Retext
    ###使用phpmailer自动邮件提醒
    Markdown学习
    有线和无线同时连接,选择其一上网
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10169620.html
Copyright © 2011-2022 走看看