• 关于轻重边及树链剖分该怎么写...


    AC BZOJ 1787 轻重边剖分LCA

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42 
     43 //==============================================================================
     44 //==============================================================================
     45 //==============================================================================
     46 //==============================================================================
     47 
     48 const int INF=(1<<28)-1;
     49 
     50 
     51 struct edge
     52 { int in; edge*nxt; };
     53 edge*eds[505000];
     54 int ecnt=10000;
     55 edge*et;
     56 void addedge(int a,int b)
     57 {
     58     if(ecnt==10000) { ecnt=0; et=new edge[10000]; }
     59     et->in=b; et->nxt=eds[a]; eds[a]=et++;
     60     ecnt++;
     61 }
     62 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
     63 
     64 //nodes 
     65 int f[505000]; //father node
     66 int ch[505000]; //chain
     67 int dep[505000]; //depth of node
     68 
     69 //chains
     70 int ctot=0;
     71 int h[505000]; //head of chain
     72 
     73 int n,m,k;
     74 
     75 int BuildTree(int x)
     76 {
     77     int sum=0;
     78     int mx=0;
     79     int mxp=-1;
     80     
     81     FOREACH_EDGE(e,x)
     82     if(e->in!=f[x])
     83     {
     84         dep[e->in]=dep[x]+1;
     85         f[e->in]=x;
     86         int v=BuildTree(e->in);
     87         sum+=v;
     88         if(v>mx)
     89         {
     90             mx=v;
     91             mxp=e->in;
     92         }
     93     }
     94     
     95     if(mxp==-1) //leaf
     96     {
     97         ch[x]=ctot;
     98         h[ctot]=x;
     99         ctot++;
    100     }
    101     else
    102     {
    103         ch[x]=ch[mxp];
    104         h[ch[x]]=x;
    105     }
    106     
    107     return sum+1;
    108 }
    109 
    110 
    111 int getlca(int a,int b)
    112 {
    113     while(ch[a]!=ch[b])
    114     {
    115         if(dep[h[ch[a]]]<dep[h[ch[b]]]) swap(a,b);
    116         a=f[h[ch[a]]];
    117     }
    118     return dep[a]>dep[b] ? b : a;
    119 }
    120 
    121 int dist(int a,int b)
    122 {
    123     int lca=getlca(a,b);
    124     return dep[a]+dep[b]-dep[lca]-dep[lca];
    125 }
    126 
    127 int main()
    128 {    
    129     n=getint();
    130     m=n-1;
    131     k=getint();
    132     for(int i=0;i<m;i++)
    133     {
    134         int a=getint()-1;
    135         int b=getint()-1;
    136         addedge(a,b);
    137         addedge(b,a);
    138     }
    139     
    140     BuildTree(0);
    141     
    142     for(int i=0;i<k;i++)
    143     {
    144         int a=getint()-1;
    145         int b=getint()-1;
    146         int c=getint()-1;
    147         int l1=getlca(a,b);
    148         int l2=getlca(b,c);
    149         int l3=getlca(a,c);
    150         
    151         int resp,resd;
    152         
    153         if(l1==l2)
    154         {
    155             resp=l3;
    156             resd=dist(a,l3)+dist(b,l3)+dist(c,l3);
    157         }
    158         else if(l2==l3)
    159         {
    160             resp=l1;
    161             resd=dist(a,l1)+dist(b,l1)+dist(c,l1);
    162         }
    163         else if(l1==l3)
    164         {
    165             resp=l2;
    166             resd=dist(a,l2)+dist(b,l2)+dist(c,l2);
    167         }
    168         
    169         printf("%d %d\n",resp+1,resd);
    170     }
    171     
    172     return 0;
    173 }
    View Code

    题解好神......两两求LCA,选择那个非公共LCA.....怎么做到的.....

    看起来HLD打熟练了应该是很好写的.....

    代码的运行时间拿了个rank8...

     

    AC BZOJ 3631 树链剖分

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21 typedef long double ldb;
     22  
     23 using namespace std;
     24  
     25 inline int getint()
     26 {
     27     int res=0;
     28     char c=getchar();
     29     bool mi=false;
     30     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     31     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     32     return mi ? -res : res;
     33 }
     34 inline ll getll()
     35 {
     36     ll res=0;
     37     char c=getchar();
     38     bool mi=false;
     39     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     40     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     41     return mi ? -res : res;
     42 }
     43 
     44 //==============================================================================
     45 //==============================================================================
     46 //==============================================================================
     47 //==============================================================================
     48 
     49 
     50 struct edge
     51 { int in;edge*nxt; };
     52 int ecnt=4000; edge*et; edge*eds[305000];
     53 void addedge(int a,int b)
     54 {
     55     if(ecnt==4000) { et=new edge[4000]; ecnt=0; }
     56     et->in=b; et->nxt=eds[a]; eds[a]=et++; ecnt++;
     57 }
     58 #define FOREACH_EDGE(i,x) for(edge*i=eds[x];i;i=i->nxt)
     59 
     60 int n,m;
     61 int q[305000];
     62 
     63 int f[305000]; //father of node.
     64 int ch[305000],chtot; //chain of node.
     65 int ct[305000]; //amount of chain nodes.
     66 int cb[305000]; //base pointer of chain in segTree.
     67 int h[305000]; //head of chain.
     68 int loc[305000]; //location of node.
     69 int dep[305000];
     70 int Build(int x)
     71 {
     72     int mx=0,mxp=-1,sum=0;
     73     FOREACH_EDGE(e,x)
     74     if(e->in!=f[x])
     75     {
     76         int s=e->in;
     77         dep[s]=dep[x]+1;
     78         f[s]=x;
     79         int v=Build(s);
     80         sum+=v;
     81         if(v>mx) mx=v,mxp=s;
     82     }
     83     
     84     if(mxp==-1) { ch[x]=chtot++; loc[x]=0; }
     85     else { ch[x]=ch[mxp]; loc[x]=loc[mxp]+1; }
     86     h[ch[x]]=x;
     87     ct[ch[x]]++;
     88     
     89     return sum+1;
     90 }
     91 
     92 int getlca(int a,int b)
     93 {
     94     while(ch[a]!=ch[b])
     95     {
     96         if(dep[h[ch[a]]]<dep[h[ch[b]]]) swap(a,b);
     97         a=f[h[ch[a]]];
     98     }
     99     return dep[a]>dep[b] ? b : a;
    100 }
    101 
    102 //Segment Tree
    103 int tag[1205000];
    104 int cl,cr,cv=1;
    105 void Change(int x=1,int l=0,int r=n-1)
    106 {
    107     if(cl<=l && r<=cr) { tag[x]+=cv; return ; }
    108     int mid=(l+r)>>1;
    109     if(mid>=cl) Change(x<<1,l,mid);
    110     if(mid<cr) Change(x<<1|1,mid+1,r);
    111 }
    112 int Query(int p) //single point query
    113 {
    114     int l=0,r=n-1,x=1;
    115     ll res=0;
    116     while(l!=r)
    117     {
    118         res+=tag[x];
    119         int mid=(l+r)>>1;
    120         if(p<=mid) { r=mid; x<<=1; }
    121         else { l=mid+1; x<<=1; x|=1; }
    122     }
    123     res+=tag[x];
    124     return res;
    125 }
    126 
    127 void addpath(int a,int fa) //directly add head and tail.Sub when counting.
    128 {
    129     while(ch[a]!=ch[fa])
    130     {
    131         cl=loc[a];
    132         cr=cb[ch[a]]+ct[ch[a]]-1;
    133         if(cl<=cr) Change();
    134         a=f[h[ch[a]]];
    135     }
    136     cl=loc[a];
    137     cr=loc[fa];
    138     Change();
    139 }
    140 
    141 int res[305000];
    142 
    143 int main()
    144 {
    145     n=getint();
    146     for(int i=0;i<n;i++) q[i]=getint()-1;
    147     
    148     for(int i=0;i<n-1;i++)
    149     {
    150         int a=getint()-1;
    151         int b=getint()-1;
    152         addedge(a,b); addedge(b,a);
    153     }
    154     f[0]=0; dep[0]=0;
    155     
    156     Build(0);
    157     
    158     int s=0;
    159     for(int i=0;i<chtot;i++)
    160     cb[i]=s,s+=ct[i];
    161     
    162     for(int i=0;i<n;i++)
    163     loc[i]+=cb[ch[i]];
    164     
    165     for(int i=1;i<n;i++)
    166     {
    167         int a=q[i-1];
    168         int b=q[i];
    169         int lca=getlca(a,b);
    170         if(lca==a) { addpath(b,lca); }
    171         else if(lca==b) { addpath(a,lca); }
    172         else
    173         {
    174             addpath(a,lca);
    175             addpath(b,lca);
    176             res[lca]--;
    177         }
    178         res[b]--;
    179     }
    180     
    181     for(int i=0;i<n;i++) printf("%d\n",res[i]+Query(loc[i]));
    182     
    183     return 0;
    184 }
    View Code

    要求支持树上一条链上的所有点点权加一.

    怪不得都说HLD好写=.=真的不难写.....速度比倍增快一个档次.....

     

     

     

    AC BZOJ1036 树链

      1 #include <cstdio>
      2 #include <iostream>
      3 
      4 #include <cstdlib>
      5 #include <cstring>
      6 #include <algorithm>
      7 #include <cmath>
      8 
      9 #include <queue>
     10 #include <vector>
     11 #include <map>
     12 #include <set>
     13 #include <stack>
     14 #include <list>
     15 
     16 typedef unsigned int uint;
     17 typedef long long int ll;
     18 typedef unsigned long long int ull;
     19 typedef double db;
     20 
     21 using namespace std;
     22 
     23 inline int getint()
     24 {
     25     int res=0;
     26     char c=getchar();
     27     bool mi=false;
     28     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     29     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     30     return mi ? -res : res;
     31 }
     32 
     33 
     34 const int INF=(1<<30)-1;
     35 
     36 int n;
     37 
     38 
     39 int a[30050];
     40 
     41 
     42 //Segment Tree
     43 ll sum[240000];
     44 int mx[240000];
     45 
     46 void update(const int&x)
     47 {
     48     sum[x]=sum[x<<1]+sum[x<<1|1];
     49     mx[x]=max(mx[x<<1],mx[x<<1|1]);
     50 }
     51 
     52 void Build(const int&x=1,const int&l=0,const int&r=n-1)
     53 {
     54     if(l==r) { mx[x]=sum[x]=a[l]; return ; }
     55     int mid=(l+r)>>1;
     56     Build(x<<1,l,mid);
     57     Build(x<<1|1,mid+1,r);
     58     update(x);
     59 }
     60 
     61 int cp,cv;
     62 void Change(const int&x=1,const int&l=0,const int&r=n-1)
     63 {
     64     if(cp<l || r<cp) return ;
     65     if(l==r) { mx[x]=sum[x]=cv; return ; }
     66     int mid=(l+r)>>1;
     67     Change(x<<1,l,mid);
     68     Change(x<<1|1,mid+1,r);
     69     update(x);
     70 }
     71 
     72 int ql,qr;
     73 int QueryMax(const int&x=1,const int&l=0,const int&r=n-1)
     74 {
     75     if(qr<l || r<ql) return -INF;
     76     if(ql<=l && r<=qr) return mx[x];
     77     int mid=(l+r)>>1;
     78     return max(
     79     QueryMax(x<<1,l,mid),
     80     QueryMax(x<<1|1,mid+1,r));
     81 }
     82 ll QuerySum(int x=1,int l=0,int r=n-1)
     83 {
     84     if(qr<l || r<ql) return 0;
     85     if(ql<=l && r<=qr) return sum[x];
     86     int mid=(l+r)>>1;
     87     return QuerySum(x<<1,l,mid) + QuerySum(x<<1|1,mid+1,r);
     88 }
     89 
     90 //End of Segment Tree
     91 
     92 struct edge
     93 {
     94     int in;
     95     edge*nxt;
     96 }pool[80000];
     97 edge*et=pool;
     98 edge*eds[30050];
     99 void addedge(int a,int b)
    100 {
    101     et->in=a; et->nxt=eds[b]; eds[b]=et++;
    102     et->in=b; et->nxt=eds[a]; eds[a]=et++;
    103 }
    104 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
    105 
    106 int c[30050],ctot; //chain code
    107 int h[30050]; //head node of chain this node stands
    108 bool t[30050]; //is this node a tail of a chain?
    109 int f[30050]; //father node
    110 int id[30050]; //location in segment
    111 int dep[30050]; //depth
    112 
    113 int DFS(int x,int cd)
    114 {
    115     dep[x]=cd;
    116     int sum=0;
    117     int m=0;
    118     int p=-1;
    119     FOREACH_EDGE(i,x)
    120     if(i->in!=f[x])
    121     {
    122         f[i->in]=x;
    123         int h=DFS(i->in,cd+1);
    124         sum+=h;
    125         if(m<h)
    126         {
    127             m=h;
    128             p=i->in;
    129         }
    130     }
    131     
    132     if(p==-1) c[x]=ctot++,t[x]=true; //start a new chain
    133     else c[x]=c[p]; //Insert this node to a chain
    134     
    135     return sum+1;
    136 }
    137 
    138 inline int GetMax(int a,int b)
    139 {
    140     int res=-INF;
    141     while(c[a]!=c[b])
    142     {
    143         if(dep[h[c[a]]]<dep[h[c[b]]]) swap(a,b);
    144         int&top=h[c[a]];
    145         ql=id[a];
    146         qr=id[top];
    147         res=max(res,QueryMax());
    148         a=f[top];
    149     }
    150     
    151     ql=min(id[a],id[b]);
    152     qr=max(id[a],id[b]);
    153     res=max(res,QueryMax());
    154     
    155     return res;
    156 }
    157 
    158 inline ll GetSum(int a,int b)
    159 {
    160     ll res=0;
    161     while(c[a]!=c[b])
    162     {
    163         if(dep[h[c[a]]]<dep[h[c[b]]]) swap(a,b);
    164         int&top=h[c[a]];
    165         ql=id[a];
    166         qr=id[top];
    167         res+=QuerySum();
    168         a=f[top];
    169     }
    170     
    171     ql=min(id[a],id[b]);
    172     qr=max(id[a],id[b]);
    173     res+=QuerySum();
    174     
    175     return res;
    176 }
    177 
    178 inline void Edit(int a,ll p)
    179 {
    180     cp=id[a];
    181     cv=p;
    182     Change();
    183 }
    184 
    185 
    186 int main()
    187 {
    188     n=getint();
    189     for(int i=0;i<n-1;i++)
    190     addedge(getint()-1,getint()-1);
    191     
    192     f[0]=0;
    193     DFS(0,0);
    194     
    195     //assign nodes to the segment tree
    196     int base=0;
    197     for(int i=0;i<n;i++)
    198     if(t[i])
    199     {
    200         int x=i;
    201         while(true)
    202         {
    203             id[x]=base++;
    204             if(c[f[x]]==c[x] && x!=0) x=f[x];
    205             else break;
    206         }
    207         h[c[x]]=x;
    208     }
    209     
    210     for(int i=0;i<n;i++)
    211     a[id[i]]=getint();
    212     
    213     Build();
    214     
    215     //deal all query
    216     int q=getint();
    217     for(int d=0;d<q;d++)
    218     {
    219         char inp[8];
    220         scanf("%s",inp);
    221         
    222         switch(inp[3])
    223         {
    224             case 'X': //QMAX
    225             {
    226                 int l=getint()-1;
    227                 int r=getint()-1;
    228                 printf("%d\n",GetMax(l,r));
    229             }
    230             break;
    231             case 'M': //QSUM
    232             {
    233                 int l=getint()-1;
    234                 int r=getint()-1;
    235                 printf("%lld\n",GetSum(l,r));
    236             }
    237             break;
    238             case 'N': //CHANGE
    239             {
    240                 int p=getint()-1;
    241                 int v=getint();
    242                 Edit(p,v);
    243             }
    244             break;
    245             default:break;
    246         }
    247         
    248     }
    249     
    250     return 0;
    251 }
    View Code

     


    写树链的大致思路:

    1.线段树.

    一棵全局线段树.......虽然牺牲了常数...但是至少不用去动态开树了=w=

    2.构造轻重边.

    这个是重点.

    首先DFS记下: 1.父节点 2.所属链号 3.节点是所属链的第几个点.

    顺便求出: 1.节点深度 2.每条链的长度(结点个数) 3.每条链的链头(深度最小的节点).

    如果当前节点是叶节点,那么新开一条链.

    如果当前节点不是叶节点,那么此节点所树链为节点最多的子树的根所属的链.

    然后在DFS之外,我们可以通过链的长度来分配全局线段树的连续空间.

    具体的假设链 $i$ 的节点数为 $t(i)$ 那么链 $i$ 线段树所维护的序列中,

    区间 ${ [\; t(i-1)+t(i-2)+...+t(0)\; ,\; t(i)+t(i-1)+t(i-2)+t(0)\; ) }$ 就是链 $i$ 所管辖的区间.

    然后按照"节点是所属链的第几个点"分配节点就好了.....

    3.查询操作

    查询(a,b)时保证a与b中a的所属链深度大于b的所属链深度.然后询问a到链头的值.

    如果是边权....嗯.....我习惯把边权压到深度较大的那个节点......于是询问的时候:

    链询问:询问a到链头的值; 然后再询问链头到它父节点(就是它本身,这个时候没必要理会)的值.

    当a,b同属一条链时,还是令a的深度大于b的深度,然后询问a到b的前一个节点的值.





     

  • 相关阅读:
    【转】EDK简单使用流程(3)
    【转】应用 printf 语句格式化输出字符
    【转】[FPGA博客大赛](updated)在xilinx的FPGA系统中scanf函数的使用
    BZOJ 1083 [SCOI2005]繁忙的都市
    BZOJ 2821 分块统计
    BZOJ 1034 [ZJOI2008]泡泡堂BNB
    BZOJ 1029 [JSOI2007]建筑抢修
    BZOJ 1096 [ZJOI2007]仓库建设
    BZOJ 1070 [SCOI2007]修车
    BZOJ 1040 [ZJOI2008]骑士
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4295947.html
Copyright © 2020-2023  润新知