• LCT小结


    LCT真是灵活好用…

    LCT的基本思想与树链剖分差不多,都是把树剖成一条条链,只不过LCT用的是SPLAY维护的,而且,SPLAY的链是会变化的,不像剖分是定死的。

    LCT最重要的操作就是access(有的地方叫expose),access(po)之后就把po到树的root这条路径变成一条链。

    具体实现的话,直接向上一直连就行了,效率可以证明是O(lgn)的。

    还有就是两个操作,link和cut。

    cut不难,直接找到这条边断掉即可。

    link的话,因为splay是用深度维护的,我们只需要access其中一个点,然后再将这个点打上翻转记号,这个点就会成为其所在的树的根,再将其接到另外一个点之下,就行了。

    接下来是代码,因为前段时间BZ倒了,所以直接上的是伍一鸣的tree。

    这题就是一个裸的LCT,splay上标记的打法与BZ的某道线段树题奇像。

    Tsinsen1303/BZOJ2631

      1 /**************************************************************
      2     Problem: 2631
      3     User: zhuohan123
      4     Language: C++
      5     Result: Accepted
      6     Time:12260 ms
      7     Memory:9836 kb
      8 ****************************************************************/
      9  
     10 #include <iostream>
     11 #include <cstdio>
     12 #include <cstring>
     13 #include <algorithm>
     14 using namespace std;
     15 typedef unsigned int uint;
     16 const int mod=51061;
     17 int n,q;
     18 struct node
     19 {
     20     int f,s[2],ws,size;//splay tree
     21     int head;//tree
     22     bool rev;
     23     uint num,sum,add,mul;
     24 }p[110000];int pnum,root;
     25 struct edge{int to,next;}g[210000];int gnum;
     26 inline void addedge(int from,int to)
     27 {
     28     g[++gnum].to=to;g[gnum].next=p[from].head;p[from].head=gnum;
     29 }
     30  
     31 inline void iadd(uint &x,uint y){x=(x+y)%mod;}
     32 inline void imul(uint &x,uint y){x=(x*y)%mod;}
     33 inline void modify(int po,uint m,uint a)
     34 {
     35     if(m!=1)
     36     {
     37         imul(p[po].num,m);
     38         imul(p[po].sum,m);
     39         imul(p[po].mul,m);
     40         imul(p[po].add,m);
     41     }
     42     if(a)
     43     {
     44         iadd(p[po].num,a);
     45         iadd(p[po].sum,a*p[po].size%mod);
     46         iadd(p[po].add,a);
     47     }
     48 }
     49 inline void reverse(int po)
     50 {
     51     if(p[po].rev)
     52     {
     53         swap(p[po].s[0],p[po].s[1]);
     54         if(p[po].s[0])p[p[po].s[0]].rev^=1,p[p[po].s[0]].ws^=1;
     55         if(p[po].s[1])p[p[po].s[1]].rev^=1,p[p[po].s[1]].ws^=1;
     56         p[po].rev^=1;
     57     }
     58 }
     59 inline void pushdown(int po)
     60 {
     61     if(p[po].mul!=1||p[po].add!=0)
     62     {
     63         if(p[po].s[0])modify(p[po].s[0],p[po].mul,p[po].add);
     64         if(p[po].s[1])modify(p[po].s[1],p[po].mul,p[po].add);
     65         p[po].mul=1;p[po].add=0;
     66     }
     67 }
     68 inline void maintain(int po)
     69 {
     70     p[po].sum=p[po].num;
     71     if(p[po].s[0])iadd(p[po].sum,p[p[po].s[0]].sum);
     72     if(p[po].s[1])iadd(p[po].sum,p[p[po].s[1]].sum);
     73     p[po].size=1;
     74     if(p[po].s[0])p[po].size+=p[p[po].s[0]].size;
     75     if(p[po].s[1])p[po].size+=p[p[po].s[1]].size;
     76 }
     77 inline void setson(int f,int s,bool ws){p[f].s[ws]=s;p[s].f=f;p[s].ws=ws;}
     78 inline bool isroot(int po)
     79 {
     80     return !p[po].f||(p[p[po].f].s[0]!=po&&p[p[po].f].s[1]!=po);
     81 }
     82 inline void rotate(int po,bool ws)
     83 {
     84     int son=p[po].s[ws];
     85     if(isroot(po))p[son].f=p[po].f;
     86     else setson(p[po].f,son,p[po].ws);
     87     setson(po,p[son].s[!ws],ws);
     88     setson(son,po,!ws);
     89     maintain(po);maintain(son);
     90 }
     91 inline int splay(int po)
     92 {
     93     while(!isroot(po))
     94     {
     95         int fa=p[po].f,gf=p[fa].f;
     96         reverse(gf);reverse(fa);reverse(po);
     97         pushdown(gf);pushdown(fa);pushdown(po);
     98         if(isroot(fa)){rotate(fa,p[po].ws);break;}
     99         if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);
    100         rotate(fa,p[po].ws);
    101     }
    102     reverse(po);
    103     pushdown(po);
    104     maintain(po);
    105     return po;
    106 }
    107 inline void access(int po)
    108 {
    109     for(int last=0;po;last=po,po=p[po].f)
    110     {
    111         splay(po);
    112         setson(po,last,1);
    113         maintain(po);
    114     }
    115 }
    116 inline void makeroot(int po)
    117 {
    118     access(po);
    119     splay(po);
    120     p[po].rev^=1;
    121 }
    122 inline void link(int u,int v)
    123 {
    124     makeroot(u);
    125     p[u].f=v;
    126 }
    127 inline void cut(int u,int v)
    128 {
    129     access(v);
    130     splay(u);
    131     if(p[u].f==v)p[u].f=0;
    132     else
    133     {
    134         access(u);splay(v);
    135         p[v].f=0;
    136     }
    137 }
    138 inline void change(int u,int v,uint m,uint a)
    139 {
    140     access(v);
    141     for(int last=0;u;last=u,u=p[u].f)
    142     {
    143         splay(u);
    144         if(!p[u].f)
    145         {
    146             if(last)modify(last,m,a);
    147             if(p[u].s[1])modify(p[u].s[1],m,a);
    148             imul(p[u].num,m);
    149             iadd(p[u].num,a);
    150         }
    151         setson(u,last,1);
    152         maintain(u);
    153     }
    154 }
    155 inline uint getans(int u,int v)
    156 {
    157     access(v);
    158     for(int last=0;u;last=u,u=p[u].f)
    159     {
    160         splay(u);
    161         if(!p[u].f)
    162         {
    163             uint ans=p[u].num;
    164             if(last)iadd(ans,p[last].sum);
    165             if(p[u].s[1])iadd(ans,p[p[u].s[1]].sum);
    166             return ans;
    167         }
    168         setson(u,last,1);
    169         maintain(u);
    170     }
    171 }
    172 void dfs(int po)
    173 {
    174     p[po].s[0]=p[po].s[1]=p[po].add=p[po].rev=0;
    175     p[po].num=p[po].sum=p[po].mul=p[po].size=1;
    176     for(int i=p[po].head;i;i=g[i].next)
    177         if(g[i].to!=p[po].f)
    178         {
    179             p[g[i].to].f=po;
    180             dfs(g[i].to);
    181         }
    182 }
    183 int main(int argc, char *argv[])
    184 {
    185     //freopen("1.in","r",stdin);freopen("1.out","w",stdout);
    186     scanf("%d%d",&n,&q);
    187     for(int i=1;i<n;i++)
    188     {
    189         int u,v;scanf("%d%d",&u,&v);
    190         addedge(u,v);addedge(v,u);
    191     }
    192     dfs(1);
    193     while(q--)
    194     {
    195         char op[5];scanf("%s",op);
    196         if(op[0]=='+')
    197         {
    198             int u,v,num;scanf("%d%d%d",&u,&v,&num);
    199             change(u,v,1,num%mod);
    200         }
    201         if(op[0]=='*')
    202         {
    203             int u,v,num;scanf("%d%d%d",&u,&v,&num);
    204             change(u,v,num%mod,0);
    205         }
    206         if(op[0]=='-')
    207         {
    208             int u1,v1,u2,v2;scanf("%d%d%d%d",&u1,&v1,&u2,&v2);
    209             cut(u1,v1);link(u2,v2);
    210         }
    211         if(op[0]=='/')
    212         {
    213             int u,v;scanf("%d%d",&u,&v);
    214             printf("%d
    ",getans(u,v));
    215         }
    216     }
    217     return 0;
    218 }

    还有一道是山东08年的省选题,就是LCT的模板题。

    题意相当于维护一个带删除的并查集。

    两个点是否在一个子树的判断,只需让两个点都一直沿着它的father跳,最后都会停在它所在的树的根所在的splay的根(好绕!!),只需判断这两个点是否相等即可。

    BZOJ2049

     1 /**************************************************************
     2     Problem: 2049
     3     User: zhuohan123
     4     Language: C++
     5     Result: Accepted
     6     Time:1244 ms
     7     Memory:4560 kb
     8 ****************************************************************/
     9  
    10 #include <iostream>
    11 #include <cstdio>
    12 #include <cstring>
    13 #include <algorithm>
    14 using namespace std;
    15 struct node{int f,s[2];bool ws,rev;}p[210000];
    16 inline bool isroot(int po){return (!p[po].f)||(p[p[po].f].s[0]!=po&&p[p[po].f].s[1]!=po);}
    17 inline void setson(int f,int s,bool ws){p[s].f=f;p[f].s[ws]=s;p[s].ws=ws;}
    18 inline void rotate(int po,bool ws)
    19 {
    20     int son=p[po].s[ws];
    21     if(isroot(po))p[son].f=p[po].f;
    22     else setson(p[po].f,son,p[po].ws);
    23     setson(po,p[son].s[!ws],ws);
    24     setson(son,po,!ws);
    25 }
    26 inline void reverse(int po)
    27 {
    28     if(p[po].rev)
    29     {
    30         swap(p[po].s[0],p[po].s[1]);
    31         p[p[po].s[0]].ws^=1;
    32         p[p[po].s[1]].ws^=1;
    33         p[p[po].s[0]].rev^=1;
    34         p[p[po].s[1]].rev^=1;
    35         p[po].rev=false;
    36     }
    37 }
    38 inline int splay(int po)
    39 {
    40     while(!isroot(po))
    41     {
    42         int fa=p[po].f,gf=p[fa].f;
    43         reverse(gf);reverse(fa);reverse(po);
    44          
    45         if(isroot(fa)){rotate(fa,p[po].ws);break;}
    46         if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);
    47         rotate(fa,p[po].ws);
    48     }
    49     reverse(po);
    50     return po;
    51 }
    52 inline void access(int po)
    53 {
    54     for(int last=0;po;last=po,po=p[po].f)
    55         setson(splay(po),last,1);
    56 }
    57 inline void makeroot(int po)
    58 {
    59     access(po);splay(po);
    60     p[po].rev^=1;
    61 }
    62 inline void link(int u,int v)
    63 {
    64     makeroot(u);p[u].f=v;
    65 }
    66 inline void cut(int u,int v)
    67 {
    68     access(u);splay(v);
    69     if(p[v].f==u)p[v].f=0;
    70     else
    71     {
    72         access(v);splay(u);
    73         p[u].f=0;
    74     }
    75 }
    76 inline bool check(int u,int v)
    77 {
    78     while(p[u].f)u=p[u].f;
    79     while(p[v].f)v=p[v].f;
    80     return u==v;
    81 }
    82 int main(int argc, char *argv[])
    83 {
    84     int n,m;scanf("%d%d",&n,&m);
    85     while(m--)
    86     {
    87         char str[30];int u,v;
    88         scanf("%s%d%d",str,&u,&v);
    89         if(str[0]=='C')link(u,v);
    90         if(str[0]=='D')cut(u,v);
    91         if(str[0]=='Q')puts(check(u,v)?"Yes":"No");
    92     }
    93     return 0;
    94 }

     接下来是最后一个……WC2006的水管局长

    题意是维护一个带link与cut的最小生成树…

    由于这棵树是会“动”的,所以不能把边权下放到点上,那么就只好把一条边变成一个点,再把这个点与两个端点相连,常数狂增不止。

    BZOJ2494

      1 /**************************************************************
      2     Problem: 2594
      3     User: zhuohan123
      4     Language: C++
      5     Result: Accepted
      6     Time:15728 ms
      7     Memory:53252 kb
      8 ****************************************************************/
      9  
     10 #include <iostream>
     11 #include <cstdio>
     12 #include <cstring>
     13 #include <algorithm>
     14 using namespace std;
     15 inline int getnum()
     16 {
     17     int ans=0;char ch=getchar();
     18     while(ch>'9'||ch<'0')ch=getchar();
     19     while(ch>='0'&&ch<='9')ans=ans*10+ch-'0',ch=getchar();
     20     return ans;
     21 }
     22 int n,m,que;
     23 struct point
     24 {
     25     int f,s[2];bool ws,rev;
     26     int num,mnum,mpos;
     27     void output(int now)
     28     {
     29         printf("%d f:%d ls:%d rs:%d rev:%d num:%d mnum:%d mpos:%d
    ",now,f,s[0],s[1],rev,num,mnum,mpos);
     30     }
     31 }p[510000];int pnum;
     32 inline void maintain(int po)
     33 {
     34     p[po].mnum=p[po].num;p[po].mpos=po;
     35     if(p[po].s[1]&&p[p[po].s[1]].mnum>p[po].mnum)
     36         p[po].mnum=p[p[po].s[1]].mnum,p[po].mpos=p[p[po].s[1]].mpos;
     37     if(p[po].s[0]&&p[p[po].s[0]].mnum>p[po].mnum)
     38         p[po].mnum=p[p[po].s[0]].mnum,p[po].mpos=p[p[po].s[0]].mpos;
     39 }
     40 inline bool isroot(int po){return (!p[po].f)||(p[p[po].f].s[0]!=po&&p[p[po].f].s[1]!=po);}
     41 inline void setson(int f,int s,bool ws){p[f].s[ws]=s;p[s].f=f;p[s].ws=ws;}
     42 inline void rotate(int po,bool ws)
     43 {
     44     int son=p[po].s[ws];
     45     if(isroot(po))p[son].f=p[po].f;
     46     else setson(p[po].f,son,p[po].ws);
     47     setson(po,p[son].s[!ws],ws);
     48     setson(son,po,!ws);
     49     maintain(po);maintain(son);
     50 }
     51 inline void reverse(int po)
     52 {
     53     if(p[po].rev)
     54     {
     55         swap(p[po].s[0],p[po].s[1]);
     56         p[p[po].s[0]].ws^=1;
     57         p[p[po].s[1]].ws^=1;
     58         p[p[po].s[0]].rev^=1;
     59         p[p[po].s[1]].rev^=1;
     60         p[po].rev=false;
     61     }
     62 }
     63 inline int splay(int po)
     64 {
     65     while(!isroot(po))
     66     {
     67         int fa=p[po].f,gf=p[fa].f;
     68         reverse(gf);reverse(fa);reverse(po);
     69         if(isroot(fa)){rotate(fa,p[po].ws);break;}
     70         if(p[fa].ws==p[po].ws)rotate(gf,p[fa].ws);
     71         rotate(fa,p[po].ws);
     72     }
     73     reverse(po);
     74     return po;
     75 }
     76 inline void access(int po)
     77 {
     78     for(int last=0;po;last=po,po=p[po].f)
     79     {
     80         splay(po);
     81         setson(po,last,1);
     82         maintain(po);
     83     }
     84 }
     85 inline void makeroot(int po)
     86 {
     87     access(po);splay(po);
     88     p[po].rev^=1;
     89 }
     90 inline void link(int u,int v)
     91 {
     92     makeroot(u);p[u].f=v;
     93 }
     94 inline void cut(int u,int v)
     95 {
     96     access(u);splay(v);
     97     if(p[v].f==u)p[v].f=0;
     98     else
     99     {
    100         access(v);splay(u);
    101         p[u].f=0;
    102     }
    103 }
    104 inline int getmax(int u,int v,int &mpos)
    105 {
    106     access(v);
    107     for(int last=0;u;last=u,u=p[u].f)
    108     {
    109         splay(u);
    110         if(!p[u].f)
    111         {
    112             int ans=p[u].num;mpos=u;
    113             if(p[u].s[1]&&ans<p[p[u].s[1]].mnum)ans=p[p[u].s[1]].mnum,mpos=p[p[u].s[1]].mpos;
    114             if(last&&ans<p[last].mnum)ans=p[last].mnum,mpos=p[last].mpos;
    115             return ans;
    116         }
    117         setson(u,last,1);
    118         maintain(u);
    119     }
    120     return 0; 
    121 }
    122 struct bian{int u,v,c,can;}b[1100000];
    123 inline bool cmp1(bian a,bian b){return a.u==b.u?a.v<b.v:a.u<b.u;}
    124 inline bool cmp2(bian a,bian b){return a.c<b.c;}
    125 struct question{int p,u,v,pos,c,ans;}q[110000];
    126 inline bool cmp3(question a,question b){return a.u==b.u?a.v<b.v:a.u<b.u;}
    127 inline bool cmp4(question a,question b){return a.pos<b.pos;}
    128 int fa[210000];
    129 int gf(int po){return fa[po]==po?po:fa[po]=gf(fa[po]);}
    130 int head[510000];
    131 struct edge{int to,next;}g[1100000];int gnum;
    132 inline void addedge(int from,int to)
    133 {
    134     g[++gnum].to=to;g[gnum].next=head[from];head[from]=gnum;
    135     g[++gnum].to=from;g[gnum].next=head[to];head[to]=gnum;
    136 }
    137 bian intree[310000];
    138 int qu[510000],ql,qr;
    139 void bfs()
    140 {
    141     ql=1;qr=0;
    142     qu[++qr]=1;
    143     while(ql<=qr)
    144         for(int now=qu[ql++],i=head[now];i;i=g[i].next)
    145         if(p[now].f!=g[i].to)
    146         p[qu[++qr]=g[i].to].f=now;
    147 }
    148 int main(int argc, char *argv[])
    149 {
    150     //freopen("1.in","r",stdin);
    151     //freopen("1.out","w",stdout);
    152     n=getnum(),m=getnum(),que=getnum();
    153     pnum=n;
    154     for(int i=1;i<=m;i++)
    155     {
    156         b[i].u=getnum(),b[i].v=getnum(),b[i].c=getnum();
    157         if(b[i].u>b[i].v)swap(b[i].u,b[i].v);
    158         b[i].can=true;
    159     }
    160     for(int i=1;i<=que;i++)
    161     {
    162         q[i].p=getnum(),q[i].u=getnum(),q[i].v=getnum();
    163         if(q[i].u>q[i].v)swap(q[i].u,q[i].v);
    164         q[i].pos=i;
    165     }
    166     sort(b+1,b+m+1,cmp1);
    167     sort(q+1,q+que+1,cmp3);
    168     for(int i=1,j=1;i<=m&&j<=que;i++)
    169     {
    170         while(j<=que&&((q[j].u<b[i].u)||(q[j].u==b[i].u&&q[j].v<b[i].v)||q[j].p==1))j++;
    171         if(j<=que&&q[j].u==b[i].u&&q[j].v==b[i].v)b[i].can=false,q[j].c=b[i].c;
    172     }
    173     for(int i=1;i<=n;i++)fa[i]=i;
    174     sort(b+1,b+m+1,cmp2);
    175     for(int i=1;i<=m;i++)
    176     if(b[i].can&&gf(b[i].u)!=gf(b[i].v))
    177     {
    178         pnum++;p[pnum].num=b[i].c;
    179         addedge(b[i].u,pnum);
    180         addedge(b[i].v,pnum);
    181         intree[pnum].u=b[i].u;intree[pnum].v=b[i].v;
    182         fa[gf(b[i].u)]=gf(b[i].v);
    183     }
    184     bfs();
    185     for(int i=1;i<=pnum;i++)p[i].mnum=p[i].num,p[i].mpos=i;
    186     sort(q+1,q+que+1,cmp4);
    187     for(int i=que;i;i--)
    188     {
    189         int mpos;
    190         if(q[i].p==1)q[i].ans=getmax(q[i].u,q[i].v,mpos);
    191         else if(getmax(q[i].u,q[i].v,mpos)>q[i].c)
    192         {
    193             cut(mpos,intree[mpos].u);
    194             cut(mpos,intree[mpos].v);
    195             intree[mpos].u=q[i].u;
    196             intree[mpos].v=q[i].v;
    197             p[mpos].num=q[i].c;
    198             link(mpos,q[i].u);
    199             link(mpos,q[i].v);
    200         }
    201     }
    202     for(int i=1;i<=que;i++)
    203         if(q[i].p==1)printf("%d
    ",q[i].ans);
    204     return 0;
    205 }
  • 相关阅读:
    整数
    mysql-5.7.13-win32 安装
    Flex air修改外部xml文件 (转)
    JAVA 取得当前目录的路径/Servlet/class/文件路径/web路径/url地址
    C#中&和&&的区别
    百度UEditor1.4.3编辑器和asp.net MVC 5结合
    ASP.NET MVC ajax数组,模型绑定问题。
    MEF依赖注入无法在在构造函数中使用的解决办法
    AJaxFileUpload 文件上传<pre>,json字符串为空解决方法
    C#中字符串转换为IPAdress
  • 原文地址:https://www.cnblogs.com/zhuohan123/p/3372889.html
Copyright © 2020-2023  润新知