專題訓練之LCA

推薦幾個博客:https://www.cnblogs.com/JVxie/p/4854719.html Tarjan離線算法的基本思路及其算法實現php

https://blog.csdn.net/shahdza/article/details/7779356 LCA題集html

http://www.cnblogs.com/zhouzhendong/p/7256007.html LCA的三種算法介紹node

 

模板(題):ios

1.(POJ1470)http://poj.org/problem?id=1470算法

Tarjan離線算法數組

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 using namespace std;  6 const int maxn=1010;  7 const int maxm=500010;  8 struct Edge{  9     int to,nxt;  10 }edge[maxn*2];  11 struct Query{  12     int q,nxt;  13     int index;  14 }query[maxm*2];  15 int f[maxn],anc[maxn];  16 bool vis[maxn];  17 int head[maxn],tot;  18 int ans[maxm],h[maxm],tt,Q;  19 bool flag[maxn];  20 int num[maxn];  21 
 22 int find(int x)  23 {  24     if ( f[x]==-1 ) return x;  25     return f[x]=find(f[x]);  26 }  27 
 28 void merge(int x,int y)  29 {  30     int fx=find(x);  31     int fy=find(y);  32     if ( fx!=fy ) f[fx]=fy;  33 }  34 
 35 void addedge(int u,int v)  36 {  37     edge[tot].to=v;  38     edge[tot].nxt=head[u];  39     head[u]=tot++;  40 }  41 
 42 void addquery(int u,int v,int index)  43 {  44     query[tt].q=v;  45     query[tt].nxt=h[u];  46     query[tt].index=index;  47     h[u]=tt++;  48     query[tt].q=u;  49     query[tt].nxt=h[v];  50     query[tt].index=index;  51     h[v]=tt++;  52 }  53 
 54 void init()  55 {  56     tot=0;  57     memset(head,-1,sizeof(head));  58     tt=0;  59     memset(h,-1,sizeof(h));  60     memset(vis,false,sizeof(vis));  61     memset(f,-1,sizeof(f));  62     memset(anc,0,sizeof(anc));  63 }  64 
 65 void LCA(int u)  66 {  67     anc[u]=u;  68     vis[u]=true;  69     for ( int i=head[u];i!=-1;i=edge[i].nxt )  70  {  71         int v=edge[i].to;  72         if ( vis[v] ) continue;  73  LCA(v);  74  merge(u,v);  75         anc[find(u)]=u;  76  }  77     for ( int i=h[u];i!=-1;i=query[i].nxt )  78  {  79         int v=query[i].q;  80         if ( vis[v] ) ans[query[i].index]=anc[find(v)];  81  }  82 }  83 
 84 int main()  85 {  86     int n,u,v,k;  87     while ( scanf("%d",&n)!=EOF )  88  {  89  init();  90         memset(flag,false,sizeof(flag));  91         for ( int i=1;i<=n;i++ )  92  {  93             scanf("%d:(%d)",&u,&k);  94             while ( k-- )  95  {  96                 scanf("%d",&v);  97                 flag[v]=true;  98  addedge(u,v);  99  addedge(v,u); 100  } 101  } 102         scanf("%d",&Q); 103         for ( int i=0;i<Q;i++ ) 104  { 105             char ch; 106             cin>>ch; 107             scanf("%d %d)",&u,&v); 108  addquery(u,v,i); 109  } 110         int root; 111         for ( int i=1;i<=n;i++ ) 112  { 113             if ( !flag[i] ) 114  { 115                 root=i; 116                 break; 117  } 118  } 119  LCA(root); 120         memset(num,0,sizeof(num)); 121         for ( int i=0;i<Q;i++ ) num[ans[i]]++; 122         for ( int i=1;i<=n;i++ ) 123  { 124             if ( num[i]>0 ) printf("%d:%d\n",i,num[i]); 125  } 126  } 127     return 0; 128 }
POJ1470

 

2.(POJ1330)http://poj.org/problem?id=1330數據結構

倍增法在線算法ide

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 using namespace std;  6 const int maxn=1e4+10;  7 const int DEG=20;  8 struct Edge{  9     int to,nxt;  10 }edge[maxn*2];  11 int head[maxn],tot;  12 int fa[maxn][DEG]; //fa[i][j]表示節點i的第2^j個祖先 
 13 int deg[maxn];  14 bool flag[maxn];  15 
 16 void addedge(int u,int v)  17 {  18     edge[tot].to=v;  19     edge[tot].nxt=head[u];  20     head[u]=tot++;  21 }  22 
 23 void init()  24 {  25     tot=0;  26     memset(head,-1,sizeof(head));  27 }  28 
 29 void BFS(int root)  30 {  31     queue<int>que;  32     deg[root]=0;  33     fa[root][0]=root;  34  que.push(root);  35     while ( !que.empty() )  36  {  37         int tmp=que.front();  38  que.pop();  39         for ( int i=1;i<DEG;i++ ) fa[tmp][i]=fa[fa[tmp][i-1]][i-1];  40         for ( int i=head[tmp];i!=-1;i=edge[i].nxt )  41  {  42             int v=edge[i].to;  43             if ( v==fa[tmp][0] ) continue;  44             deg[v]=deg[tmp]+1;  45             fa[v][0]=tmp;  46  que.push(v);  47  }  48  }  49 }  50 
 51 int LCA(int u,int v)  52 {  53     if ( deg[u]>deg[v] ) swap(u,v);  54     int hu=deg[u],hv=deg[v];  55     int tu=u,tv=v;  56     for ( int det=hv-hu,i=0;det;det>>=1,i++ )  57  {  58         if ( det&1 ) tv=fa[tv][i];  59  }  60     if ( tu==tv ) return tu;  61     for ( int i=DEG-1;i>=0;i-- )  62  {  63         if ( fa[tu][i]==fa[tv][i] ) continue;  64         tu=fa[tu][i];  65         tv=fa[tv][i];  66  }  67     return fa[tu][0];  68 }  69 
 70 int main()  71 {  72     int T,n,u,v;  73     scanf("%d",&T);  74     while ( T-- )  75  {  76         scanf("%d",&n);  77  init();  78         memset(flag,false,sizeof(flag));  79         for ( int i=1;i<n;i++ )  80  {  81             scanf("%d%d",&u,&v);  82  addedge(u,v);  83  addedge(v,u);  84             flag[v]=true;  85  }  86         int root;  87         for ( int i=1;i<=n;i++ )  88  {  89             if ( !flag[i] )  90  {  91                 root=i;  92                 break;  93  }  94  }  95  BFS(root);  96         scanf("%d%d",&u,&v);  97         printf("%d\n",LCA(u,v));  98  }  99     return 0; 100 }
POJ1330

ST+DFS在線算法優化

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=10010;  6 int rmq[maxn*2]; //即歐拉序列對應的深度序列 
 7 struct ST  8 {  9     int mm[2*maxn];  10     int dp[2*maxn][20]; //最小值對應的下標
 11     void init(int n)  12  {  13         mm[0]=-1;  14         for ( int i=1;i<=n;i++ )  15  {  16             mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];  17             dp[i][0]=i;  18  }  19         for ( int j=1;j<=mm[n];j++ )  20  {  21             for ( int i=1;i+(1<<j)-1<=n;i++ )  22  {  23                 if ( rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]] ) dp[i][j]=dp[i][j-1];  24                 else dp[i][j]=dp[i+(1<<(j-1))][j-1];  25  }  26  }  27  }  28     int query(int a,int b) //查詢[a,b] 之間最小值的下標 
 29  {  30         if ( a>b ) swap(a,b);  31         int k=mm[b-a+1];  32         if ( rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]] ) return dp[a][k];  33         else return dp[b-(1<<k)][k];  34  }  35 };  36 struct Edge{  37     int to,nxt;  38 }edge[maxn*2];  39 int tot,head[maxn];  40 int F[maxn],P[maxn],cnt; //F爲歐拉序(即DFS遍歷的順序),長度爲2*n-1,從1開始;P爲全部點第一次在F中出現的位置 
 41 ST st;  42 
 43 void init()  44 {  45     tot=0;  46     memset(head,-1,sizeof(head));  47 }  48 
 49 void addedge(int u,int v) //加邊,無向邊須要加兩次 
 50 {  51     edge[tot].to=v;  52     edge[tot].nxt=head[u];  53     head[u]=tot++;  54 }  55 
 56 void dfs(int u,int pre,int dep)  57 {  58     F[++cnt]=u;  59     rmq[cnt]=dep;  60     P[u]=cnt;  61     for ( int i=head[u];i!=-1;i=edge[i].nxt )  62  {  63         int v=edge[i].to;  64         if ( v==pre ) continue;  65         dfs(v,u,dep+1);  66         F[++cnt]=u;  67         rmq[cnt]=dep;  68  }  69 }  70 
 71 void LCA_init(int root,int num) //查詢LCA前的初始化 
 72 {  73     cnt=0;  74     dfs(root,root,0);  75     st.init(2*num-1);  76 }  77 
 78 int query(int u,int v) //查詢LCA(u,v)的編號 
 79 {  80     return F[st.query(P[u],P[v])];  81 }  82 bool flag[maxn];  83 
 84 int main()  85 {  86     int T,N,u,v;  87     scanf("%d",&T);  88     while ( T-- )  89  {  90         scanf("%d",&N);  91  init();  92         memset(flag,false,sizeof(flag));  93         for ( int i=1;i<N;i++ )  94  {  95             scanf("%d%d",&u,&v);  96  addedge(u,v);  97  addedge(v,u);  98             flag[v]=true;  99  } 100         int root; 101         for ( int i=1;i<=N;i++ ) 102  { 103             if ( !flag[i] ) 104  { 105                 root=i; 106                 break; 107  } 108  } 109  LCA_init(root,N); 110         scanf("%d%d",&u,&v); 111         printf("%d\n",query(u,v)); 112  } 113     return 0; 114 }
POJ1330

 

 

練習題:ui

1.(HDOJ2586)http://acm.hdu.edu.cn/showproblem.php?pid=2586

題意:求給定兩點之間的距離

分析:若是t是u,v的最近公共祖先,那麼d[u,v]=d[u,root]+d[v,root]-2*d[t,root],因此咱們只須要在倍增算法的BFS中每次更新深度時同時把距離一塊兒更新掉便可

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 using namespace std;  6 const int maxn=4e4+10;  7 const int DEG=20;  8 const int inf=1e9;  9 struct Edge{  10     int to,nxt,w;  11 }edge[maxn*2];  12 int head[maxn],tot;  13 int fa[maxn][DEG]; //fa[i][j]表示節點i的第2^j個祖先 
 14 int deg[maxn];  15 bool flag[maxn];  16 int n,d[maxn];  17 
 18 void addedge(int u,int v,int w)  19 {  20     edge[tot].to=v;  21     edge[tot].nxt=head[u];  22     edge[tot].w=w;  23     head[u]=tot++;  24 }  25 
 26 void init()  27 {  28     tot=0;  29     memset(head,-1,sizeof(head));  30 }  31 
 32 void BFS(int root)  33 {  34     queue<int>que;  35     for ( int i=1;i<=n;i++ ) d[i]=inf;  36     d[root]=0;  37     deg[root]=0;  38     fa[root][0]=root;  39  que.push(root);  40     while ( !que.empty() )  41  {  42         int tmp=que.front();  43  que.pop();  44         for ( int i=1;i<DEG;i++ ) fa[tmp][i]=fa[fa[tmp][i-1]][i-1];  45         for ( int i=head[tmp];i!=-1;i=edge[i].nxt )  46  {  47             int v=edge[i].to;  48             int w=edge[i].w;  49             if ( v==fa[tmp][0] ) continue;  50             deg[v]=deg[tmp]+1;  51             d[v]=min(d[v],d[tmp]+w);  52             fa[v][0]=tmp;  53  que.push(v);  54  }  55  }  56 }  57 
 58 int LCA(int u,int v)  59 {  60     if ( deg[u]>deg[v] ) swap(u,v);  61     int hu=deg[u],hv=deg[v];  62     int tu=u,tv=v;  63     for ( int det=hv-hu,i=0;det;det>>=1,i++ )  64  {  65         if ( det&1 ) tv=fa[tv][i];  66  }  67     if ( tu==tv ) return tu;  68     for ( int i=DEG-1;i>=0;i-- )  69  {  70         if ( fa[tu][i]==fa[tv][i] ) continue;  71         tu=fa[tu][i];  72         tv=fa[tv][i];  73  }  74     return fa[tu][0];  75 }  76 
 77 int main()  78 {  79     int T,u,v,w,m,x,ans;  80     scanf("%d",&T);  81     while ( T-- )  82  {  83         scanf("%d%d",&n,&m);  84  init();  85         memset(flag,false,sizeof(flag));  86         for ( int i=1;i<n;i++ )  87  {  88             scanf("%d%d%d",&u,&v,&w);  89  addedge(u,v,w);  90  addedge(v,u,w);  91             flag[v]=true;  92  }  93         int root;  94         for ( int i=1;i<=n;i++ )  95  {  96             if ( !flag[i] )  97  {  98                 root=i;  99                 break; 100  } 101  } 102  BFS(root); 103         for ( int i=1;i<=m;i++ ) 104  { 105             scanf("%d%d",&u,&v); 106             x=LCA(u,v); 107             ans=d[u]+d[v]-2*d[x]; 108             printf("%d\n",ans); 109  } 110  } 111     return 0; 112 }
HDOJ2586

 

2.(HDOJ2874)http://acm.hdu.edu.cn/showproblem.php?pid=2874

題意:給出一個森林,求給定兩點之間的距離

分析:Tarjan離線算法,有多個根節點,每次詢問時判斷兩個點是否處於同一個樹上。LCA傳入參數時須要傳入當前的點,距離根節點的距離,根節點的編號。可是此題卡內存

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 using namespace std;  6 const int maxn=1e4+10;  7 const int maxm=1e6+10;  8 struct Edge{  9     int to,nxt,w;  10 }edge[maxn*2];  11 struct Query{  12     int q,nxt;  13     int index;  14 }query[maxm*2];  15 int f[maxn],anc[maxn];  16 int head[maxn],tot;  17 int ans[maxm],h[maxm],tt,Q,belong[maxn];  18 int n,d[maxn];  19 
 20 int find(int x)  21 {  22     if ( f[x]==-1 ) return x;  23     return f[x]=find(f[x]);  24 }  25 
 26 void merge(int x,int y)  27 {  28     int fx=find(x);  29     int fy=find(y);  30     if ( fx!=fy ) f[fx]=fy;  31 }  32 
 33 void addedge(int u,int v,int w)  34 {  35     edge[tot].to=v;  36     edge[tot].nxt=head[u];  37     edge[tot].w=w;  38     head[u]=tot++;  39 }  40 
 41 void addquery(int u,int v,int index)  42 {  43     query[tt].q=v;  44     query[tt].nxt=h[u];  45     query[tt].index=index;  46     h[u]=tt++;  47     query[tt].q=u;  48     query[tt].nxt=h[v];  49     query[tt].index=index;  50     h[v]=tt++;  51 }  52 
 53 void init()  54 {  55     tot=0;  56     memset(head,-1,sizeof(head));  57     tt=0;  58     memset(h,-1,sizeof(h));  59     memset(f,-1,sizeof(f));  60     memset(anc,0,sizeof(anc));  61 }  62 
 63 void LCA(int u,int deep,int root)  64 {  65     anc[u]=u;  66     belong[u]=root;  67     d[u]=deep;  68     for ( int i=head[u];i!=-1;i=edge[i].nxt )  69  {  70         int v=edge[i].to;  71         int w=edge[i].w;  72         if ( belong[v]!=-1 ) continue;  73         LCA(v,deep+w,root);  74  merge(u,v);  75         anc[find(u)]=u;  76  }  77     for ( int i=h[u];i!=-1;i=query[i].nxt )  78  {  79         int v=query[i].q;  80         if ( belong[v]==root )  81  {  82             int sum=d[u]+d[v]-2*d[anc[find(v)]];  83             ans[query[i].index]=sum;  84  }  85  }  86 }  87 
 88 int main()  89 {  90     int u,v,w,k,m,q,x;  91     while ( scanf("%d%d%d",&n,&m,&Q)!=EOF )  92  {  93  init();  94         for ( int i=1;i<=m;i++ )  95  {  96             scanf("%d%d%d",&u,&v,&w);  97  addedge(u,v,w);  98  addedge(v,u,w);  99  } 100         for ( int i=0;i<Q;i++ ) 101  { 102             ans[i]=-1; 103             scanf("%d%d",&u,&v); 104  addquery(u,v,i); 105  } 106         memset(belong,-1,sizeof(belong)); 107         memset(d,-1,sizeof(d)); 108         for ( int i=1;i<=n;i++ ) 109  { 110             if ( belong[i]==-1 ) LCA(i,0,i); 111  } 112         for ( int i=0;i<Q;i++ ) 113  { 114             if ( ans[i]!=-1 ) printf("%d\n",ans[i]); 115             else printf("Not connected\n"); 116  } 117  } 118     return 0; 119 }
HDOJ2874(MLE)
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #include<vector>
 6 using namespace std;  7 typedef long long LL;  8 
 9 const int maxm=2e4+10;  10 const int maxn=1e4+10;  11 const int maxq=2e6+10;  12 struct Node{  13     int to;  14     int w;  15     int next;  16 }e[maxm];  17 int eh[maxn],dis[maxn],pre[maxn],etol,vis[maxn];  18 struct Query{  19     int to;  20     int index;  21     int next;  22 }qe[maxq];  23 int qh[maxn],ans[maxq/2],qtol;  24 int n,m,c;  25 
 26 void init()  27 {  28     etol=qtol=0;  29     memset(eh,-1,sizeof(eh));  30     memset(qh,-1,sizeof(qh));  31 }  32 
 33 void add1(int u,int v,int w)  34 {  35     e[etol].to=v;  36     e[etol].w=w;  37     e[etol].next=eh[u];  38     eh[u]=etol++;  39 }  40 
 41 void add2(int u,int v,int id)  42 {  43     qe[qtol].index=id;  44     qe[qtol].to=v;  45     qe[qtol].next=qh[u];  46     qh[u]=qtol++;  47 }  48 
 49 int Find(int u)  50 {  51     if(pre[u]!=u) pre[u]=Find(pre[u]);  52     return pre[u];  53 }  54 
 55 void LCA(int u,int deep,int root)  56 {  57     pre[u]=u;  58     dis[u]=deep;  59     vis[u]=root;  60     for(int i=eh[u];~i;i=e[i].next)  61  {  62         int v=e[i].to;  63         if(vis[v]==-1)  64  {  65             LCA(v,deep+e[i].w,root);  66             pre[v]=u;  67  }  68  }  69     for(int i=qh[u];~i;i=qe[i].next)  70  {  71         int v=qe[i].to;  72         if(vis[v]==root)  73             ans[qe[i].index]=dis[v]+dis[u]-2*dis[Find(v)];  74  }  75 }  76 
 77 
 78 int main()  79 {  80     while(~scanf("%d%d%d",&n,&m,&c))  81  {  82         int u,v,w;  83  init();  84         while(m--)  85  {  86             scanf("%d%d%d",&u,&v,&w);  87  add1(u,v,w);  88  add1(v,u,w);  89  }  90         for(int i=0;i<c;i++)  91  {  92             scanf("%d%d",&u,&v);  93             ans[i]=-1;  94  add2(u,v,i);  95  add2(v,u,i);  96  }  97         memset(vis,-1,sizeof(vis));  98         for(int i=1;i<=n;i++){  99             if(vis[i]==-1) 100                 LCA(i,0,i); 101  } 102         for(int i=0;i<c;i++) 103  { 104             if(ans[i]==-1) puts("Not connected"); 105             else printf("%d\n",ans[i]); 106  } 107  } 108     return 0; 109 }
HDOJ2874(參考的AC代碼)

 

3.(HDOJ5044)http://acm.hdu.edu.cn/showproblem.php?pid=5044

題意:給出一顆樹,有m個操做,若爲add1 u v w表示從u到v通過點的點權都+w,add2 u v w表示從u到v通過點的邊權都+w

分析:如下解釋摘自:https://blog.csdn.net/hongrock/article/details/39616757

找到U, V的最近公共祖先X。

add[i][0]表示第i個點的權值。

des[i]表示第i個點在計算完以後,應該減小的權值。

add[i][1]表示第i個點跟其父結點之間的邊的權值。

對於操做1有:add[u][0]+=w add[v][0]+=w add[X][0]-=w des[X]+=w;

對於操做2有:add[u][1]+=w add[v][1]+=w add[X][1]-=2*w

關於操做的解釋:

對於第一種操做,確定U到X的路徑的結點增長K,V到X的路徑也增長K。

因此咱們能夠經過將add[U][0]和add[V][0]的信息不斷傳遞上去,直到X爲止。

因爲U和V都會傳遞一個K給X,因此add[X][0]減掉一個K。

處理完X了,K不能再傳給其父節點,因此再用des[X]減掉一次。

對於第二種操做,同理,也是不斷將信息向上傳遞。但因爲這裏是邊,不會算兩次,因此直接在X的位置減掉兩倍K便可。

 

完成以上後,進行bfs,每次將葉子節點(入度爲0的點)不斷投入棧中,求出每一個點/邊的權值

最後注意下N=1的時候,雖然沒有邊,可是輸出邊權仍是要留個空行給它。

注意:此題卡空間卡時間,要輸入輸出外掛,還要人工手動加棧,初始化要少等等優化

 1 #pragma comment(linker, "/STACK:1024000000,1024000000")  
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;  7 typedef long long ll;  8 const int maxn=1e5+10;  9 const int DEG=20;  10 struct Edge{  11     int to,nxt;  12 }edge[maxn*2];  13 int head[maxn],tot;  14 int fa[maxn][DEG]; //fa[i][j]表示節點i的第2^j個祖先 
 15 int deg[maxn];  16 ll add[maxn][2],node[maxn],edg[maxn],des[maxn];  17 int du[maxn],tp[maxn];  18 bool flag[maxn];  19 
 20 void addedge(int u,int v)  21 {  22     edge[tot].to=v;  23     edge[tot].nxt=head[u];  24     head[u]=tot++;  25 }  26 
 27 void init()  28 {  29     tot=0;  30     memset(head,-1,sizeof(head));  31 }  32 
 33 void BFS(int root)  34 {  35     queue<int>que;  36     deg[root]=0;  37     fa[root][0]=root;  38  que.push(root);  39     while ( !que.empty() )  40  {  41         int tmp=que.front();  42  que.pop();  43         for ( int i=1;i<DEG;i++ ) fa[tmp][i]=fa[fa[tmp][i-1]][i-1];  44         for ( int i=head[tmp];i!=-1;i=edge[i].nxt )  45  {  46             int v=edge[i].to;  47             if ( v==fa[tmp][0] ) continue;  48             tp[v]=i/2+1;  49             du[tmp]++;  50             deg[v]=deg[tmp]+1;  51             fa[v][0]=tmp;  52  que.push(v);  53  }  54  }  55 }  56 
 57 int LCA(int u,int v)  58 {  59     if ( deg[u]>deg[v] ) swap(u,v);  60     int hu=deg[u],hv=deg[v];  61     int tu=u,tv=v;  62     for ( int det=hv-hu,i=0;det;det>>=1,i++ )  63  {  64         if ( det&1 ) tv=fa[tv][i];  65  }  66     if ( tu==tv ) return tu;  67     for ( int i=DEG-1;i>=0;i-- )  68  {  69         if ( fa[tu][i]==fa[tv][i] ) continue;  70         tu=fa[tu][i];  71         tv=fa[tv][i];  72  }  73     return fa[tu][0];  74 }  75 
 76 void bfs(int n)  77 {  78     queue<int>que;  79     for ( int i=1;i<=n;i++ )  80  {  81         if ( !du[i] ) que.push(i);  82  }  83     while ( !que.empty() )  84  {  85         int u=que.front();  86  que.pop();  87         node[u]=add[u][0];  88         add[u][0]-=des[u];  89         int v=fa[u][0];  90         add[v][0]+=add[u][0];  91         add[v][1]+=add[u][1];  92         edg[tp[u]]+=add[u][1];  93         if ( !(--du[v]) ) que.push(v);  94  }  95 }  96 
 97 inline bool scan_d(int &num)  98 {  99     char in;bool IsN=false; 100     in=getchar(); 101     if(in==EOF) return false; 102     while(in!='-'&&(in<'0'||in>'9')) in=getchar(); 103     if(in=='-'){ IsN=true;num=0;} 104     else num=in-'0'; 105     while(in=getchar(),in>='0'&&in<='9'){ 106             num*=10,num+=in-'0'; 107  } 108     if(IsN) num=-num; 109     return true; 110 } 111 
112 inline void out(long long x) { 113     if(x>9) out(x/10); 114     putchar(x%10+'0'); 115 } 116 
117 int main() 118 { 119     int T,n,u,v,w,q,h,l; 120     char op[10]; 121  scan_d(T); 122     for ( h=1;h<=T;h++ ) 123  { 124  scan_d(n); 125  scan_d(q); 126  init(); 127         for ( int i=1;i<=n;i++ ) 128  { 129             //flag[i]=false;
130             add[i][0]=add[i][1]=0; 131             des[i]=du[i]=node[i]=edg[i]=0; 132  } 133         //memset(flag,false,sizeof(flag)); 134         //memset(add,0,sizeof(add)); 135         //memset(des,0,sizeof(des)); 136         //memset(du,0,sizeof(du)); 137         //memset(node,0,sizeof(node)); 138         //memset(edg,0,sizeof(edg));
139         for ( int i=1;i<n;i++ ) 140  { 141  scan_d(u); 142  scan_d(v); 143  addedge(u,v); 144  addedge(v,u); 145  } 146         int root=1; 147         /*
148  for ( int i=1;i<=n;i++ ) 149  { 150  if ( !flag[i] ) 151  { 152  root=i; 153  break; 154  } 155  } 156         */
157  BFS(root); 158         while ( q-- ) 159  { 160             scanf("%s",op); 161  scan_d(u); 162  scan_d(v); 163  scan_d(w); 164             l=LCA(u,v); 165             if ( op[3]=='1' ) 166  { 167                 add[u][0]+=w; 168                 add[v][0]+=w; 169                 add[l][0]-=w; 170                 des[l]+=w; 171  } 172             else
173  { 174                 add[u][1]+=w; 175                 add[v][1]+=w; 176                 add[l][1]-=2*w; 177  } 178  } 179  bfs(n); 180         printf("Case #%d:\n",h); 181         for ( int i=1;i<=n;i++ ) 182  { 183             out(node[i]); 184             if ( i!=n ) printf(" "); 185             else printf("\n"); 186  } 187         for ( int i=1;i<n;i++ ) 188  { 189             out(edg[i]); 190             if ( i!=(n-1) ) printf(" "); 191             else printf("\n"); 192  } 193         if ( n==1 ) printf("\n"); 194  } 195     return 0; 196 }
HDOJ5044(TLE)

 

4.(HDOJ4547)http://acm.hdu.edu.cn/showproblem.php?pid=4547

分析:從節點a出發,a到任意一個子節點只須要1步,a到任意一個父節點爲兩個點的距離差。因此詢問給出u,v時,先求出l=lca(u,v),ans=dis[u]-dis[l],若是v於l不是同一個點則ans++(從l一步到達v)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #include<map>
 6 #include<string>
 7 #include<iostream>
 8 using namespace std;  9 const int maxn=1e5+10;  10 const int DEG=20;  11 struct Edge{  12     int to,nxt,w;  13 }edge[maxn*2];  14 int head[maxn],tot;  15 int fa[maxn][DEG]; //fa[i][j]表示節點i的第2^j個祖先 
 16 int deg[maxn];  17 bool flag[maxn];  18 int dis[maxn];  19 map<string,int>mp;  20 
 21 void addedge(int u,int v,int w)  22 {  23     edge[tot].to=v;  24     edge[tot].nxt=head[u];  25     edge[tot].w=w;  26     head[u]=tot++;  27 }  28 
 29 void init()  30 {  31     tot=0;  32     memset(head,-1,sizeof(head));  33 }  34 
 35 void BFS(int root)  36 {  37     queue<int>que;  38     deg[root]=0;  39     fa[root][0]=root;  40  que.push(root);  41     while ( !que.empty() )  42  {  43         int tmp=que.front();  44  que.pop();  45         for ( int i=1;i<DEG;i++ ) fa[tmp][i]=fa[fa[tmp][i-1]][i-1];  46         for ( int i=head[tmp];i!=-1;i=edge[i].nxt )  47  {  48             int v=edge[i].to;  49             int w=edge[i].w;  50             if ( v==fa[tmp][0] ) continue;  51             dis[v]=dis[tmp]+w;  52             deg[v]=deg[tmp]+1;  53             fa[v][0]=tmp;  54  que.push(v);  55  }  56  }  57 }  58 
 59 int LCA(int u,int v)  60 {  61     if ( deg[u]>deg[v] ) swap(u,v);  62     int hu=deg[u],hv=deg[v];  63     int tu=u,tv=v;  64     for ( int det=hv-hu,i=0;det;det>>=1,i++ )  65  {  66         if ( det&1 ) tv=fa[tv][i];  67  }  68     if ( tu==tv ) return tu;  69     for ( int i=DEG-1;i>=0;i-- )  70  {  71         if ( fa[tu][i]==fa[tv][i] ) continue;  72         tu=fa[tu][i];  73         tv=fa[tv][i];  74  }  75     return fa[tu][0];  76 }  77 
 78 int main()  79 {  80     int T,n,q,u,v,w,num,l,ans;  81     string s1,s2;  82     scanf("%d",&T);  83     while ( T-- )  84  {  85         scanf("%d%d",&n,&q);  86  mp.clear();  87  init();  88         num=0;  89         memset(flag,false,sizeof(flag));  90         memset(dis,0,sizeof(dis));  91         for ( int i=1;i<n;i++ )  92  {  93             cin>>s1>>s2;  94             if ( !mp[s1] ) mp[s1]=++num;  95             if ( !mp[s2] ) mp[s2]=++num;  96             v=mp[s1];  97             u=mp[s2];  98             addedge(u,v,1);  99             flag[v]=true; 100  } 101         int root; 102         for ( int i=1;i<=n;i++ ) 103  { 104             if ( !flag[i] ) 105  { 106                 root=i; 107                 break; 108  } 109  } 110  BFS(root); 111         while ( q-- ) 112  { 113             cin>>s1>>s2; 114             u=mp[s1]; 115             v=mp[s2]; 116             l=LCA(u,v); 117             ans=dis[u]-dis[l]; 118             if ( l!=v ) ans++; 119             printf("%d\n",ans); 120  } 121  } 122     return 0; 123 }
HDOJ4547

 

5.(HDOJ5274)http://acm.hdu.edu.cn/showproblem.php?pid=5274

題意:有一顆樹,有n個點,每一個點都有個點權。如今有q個詢問,總共有兩種操做
0 x y表明把編號爲x點的權值變成y

1 x y求出點x到點y的路徑上出現點權值爲奇數的點,若都爲偶數則輸出-1。題目保證最多隻有一個爲奇數的點權值

分析:官方題解:

題目裏有一個很神奇的性質:路徑上最多隻有一個數出現奇數次。

這應該立刻想到異或。由於異或兩次和沒異或是等價的。此外異或知足區間減性質。

由於有修改,咱們很天然地想到用數據結構維護。

最無腦的就是直接上樹鏈剖分或是Splay維護區間xor值便可。

仔細想想,發現能夠利用LCA消去「樹上路徑」,轉化爲根到x路徑上求xor值。

咱們能夠很經典地直接使用線段樹或樹狀數組維護dfs序。 

有一個很強的trick就是權值能夠爲0!

因此好比路徑上有3個0,雖然他們xor值仍是0,可是他們是出現了奇數次。

我特地把A[i]說成∈天然數集而不是[0,100000][0,100000][0,100000],就是想盡可能不被發現。

怎麼避免呢?單獨維護0的狀況?

有一個很簡單的解決方案:直接把讀入時全部權值+1,輸出的時候再-1便可!

時間複雜度爲O(N∗log(N)2)或者O(N∗log(N))

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=1e5+10;  6 int rmq[maxn*2];  7 struct ST  8 {  9     int mm[2*maxn];  10     int dp[2*maxn][20];  11     void init(int n)  12  {  13         mm[0]=-1;  14         for ( int i=1;i<=n;i++ )  15  {  16             mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];  17             dp[i][0]=i;  18  }  19         for ( int j=1;j<=mm[n];j++ )  20  {  21             for ( int i=1;i+(1<<j)-1<=n;i++ )  22  {  23                 if ( rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]] ) dp[i][j]=dp[i][j-1];  24                 else dp[i][j]=dp[i+(1<<(j-1))][j-1];  25  }  26  }  27  }  28     int query(int a,int b)  29  {  30         if ( a>b ) swap(a,b);  31         int k=mm[b-a+1];  32         if ( rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]] ) return dp[a][k];  33         else return dp[b-(1<<k)][k];  34  }  35 };  36 struct Edge{  37     int to,nxt;  38 }edge[maxn*2];  39 int tot,head[maxn],in[maxn],out[maxn];  40 int F[maxn],P[maxn],cnt,now,val[maxn];  41 int bit[maxn*2];  42 ST st;  43 
 44 int lowbit(int x)  45 {  46     return x&(-x);  47 }  48 
 49 void add(int k,int num)  50 {  51     while ( k<maxn*2 )  52  {  53         bit[k]^=num;  54         k+=lowbit(k);  55  }  56 }  57 
 58 int sum(int k)  59 {  60     int s=0;  61     while ( k )  62  {  63         s^=bit[k];  64         k-=lowbit(k);  65  }  66     return s;  67 }  68 
 69 void init()  70 {  71     tot=0;  72     memset(head,-1,sizeof(head));  73 }  74 
 75 void addedge(int u,int v)  76 {  77     edge[tot].to=v;  78     edge[tot].nxt=head[u];  79     head[u]=tot++;  80 }  81 
 82 void dfs(int u,int pre,int dep)  83 {  84     F[++cnt]=u;  85     in[u]=++now;  86     rmq[cnt]=dep;  87     P[u]=cnt;  88     for ( int i=head[u];i!=-1;i=edge[i].nxt )  89  {  90         int v=edge[i].to;  91         if ( v==pre ) continue;  92         dfs(v,u,dep+1);  93         F[++cnt]=u;  94         rmq[cnt]=dep;  95  }  96     out[u]=++now;  97 }  98 
 99 void LCA_init(int root,int num) 100 { 101     cnt=0; 102     now=0; 103     dfs(root,root,0); 104     st.init(2*num-1); 105 } 106 
107 int query(int u,int v) 108 { 109     return F[st.query(P[u],P[v])]; 110 } 111 bool flag[maxn]; 112 
113 int main() 114 { 115     int T,u,v,q,op,N; 116     scanf("%d",&T); 117     while ( T-- ) 118  { 119         scanf("%d%d",&N,&q); 120  init(); 121         memset(flag,false,sizeof(flag)); 122         memset(bit,0,sizeof(bit)); 123         for ( int i=1;i<N;i++ ) 124  { 125             scanf("%d%d",&u,&v); 126  addedge(u,v); 127  addedge(v,u); 128             flag[v]=true; 129  } 130         int root; 131         for ( int i=1;i<=N;i++ ) 132  { 133             if ( !flag[i] ) 134  { 135                 root=i; 136                 break; 137  } 138  } 139  LCA_init(root,N); 140         for ( int i=1;i<=N;i++ ) 141  { 142             scanf("%d",&val[i]); 143             val[i]++; 144             add(in[i],val[i]); 145             add(out[i],val[i]); 146  } 147         //for ( int i=1;i<=N;i++ ) printf("%d %d\n",in[i],out[i]); 148         //for ( int i=1;i<=2*N;i++ ) printf("%d\n",sum(i));
149         while ( q-- ) 150  { 151             scanf("%d%d%d",&op,&u,&v); 152             if ( op==0 ) 153  { 154                 v++; 155                 add(in[u],val[u]^v); 156                 add(out[u],val[u]^v); 157                 val[u]=v; 158  } 159             else
160  { 161                 int l=query(u,v); 162                 int ans=sum(in[u])^sum(in[v])^val[l]; 163                 if ( ans==0 ) printf("-1\n"); 164                 else printf("%d\n",ans-1); 165  } 166  } 167         //for ( int i=1;i<=N;i++ ) printf("%d %d\n",in[i],out[i]); 168         //for ( int i=1;i<=2*N;i++ ) printf("%d\n",sum(i));
169  } 170     return 0; 171 }
HDOJ5274(WA)
 1 #pragma comment(linker, "/STACK:102400000,102400000")
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<algorithm>
 7 using namespace std;  8 #define MAXN 100005
 9 #define MAXM 300005
10 #define LOG 19
11 #define lowbit(i) (i & -i)
12 vector<int>vec[MAXN]; 13 int _,n,q,cnt; 14 int val[MAXN],uid[MAXN],vid[MAXN],dp[LOG][MAXM],pre[MAXM]; 15 void modify(int i,int v) 16 { 17     for(;i < MAXM;i += lowbit(i)) 18         pre[i] ^= v; 19 } 20 int sum(int i) 21 { 22     int ans = 0; 23     for(;i;i -= lowbit(i)) 24         ans ^= pre[i]; 25     return ans; 26 } 27 void dfs(int u,int fa) 28 { 29     for(int i = 0;i < vec[u].size();i++) 30  { 31         int v = vec[u][i]; 32         if(v == fa)continue; 33         uid[v] = ++cnt; 34  modify(cnt,val[v]); 35         dp[0][cnt] = v; 36  dfs(v,u); 37         vid[v] = ++cnt; 38  modify(cnt,val[v]); 39         dp[0][cnt] = u; 40  } 41 } 42 void init_rmq() 43 { 44     for(int i = 1;(1 << i) <= cnt;i++) 45         for(int j = 1;j + (1 << i) - 1 <= cnt;j++) 46             dp[i][j] = min(dp[i - 1][j],dp[i - 1][j + (1 << i - 1)]); 47 } 48 int lca(int l,int r) 49 { 50     if(l > r)swap(l,r); 51     int i = 0; 52     for(;l + (1 << i) - 1 <= r;i++); 53     i--; 54     return min(dp[i][l],dp[i][r - (1 << i) + 1]); 55 } 56 int main() 57 { 58     scanf("%d",&_); 59     while(_--) 60  { 61         scanf("%d%d",&n,&q); 62         for(int i = 0;i <= n;i++)vec[i].clear(); 63         vec[0].push_back(1) , vec[1].push_back(0); 64         memset(pre,0,sizeof(pre)); 65         for(int i = 1;i < n;i++) 66  { 67             int u,v; 68             scanf("%d%d",&u,&v); 69  vec[u].push_back(v),vec[v].push_back(u); 70  } 71         for(int i = 1;i <= n;i++) 72  { 73             scanf("%d",&val[i]); 74             val[i]++; 75  } 76         cnt = 0; 77         dfs(0,-1); 78  init_rmq(); 79         for(int i = 0;i < q;i++) 80  { 81             int c,u,v; 82             scanf("%d%d%d",&c,&u,&v); 83             if(c == 0) 84  { 85                 v++; 86                 modify(uid[u],val[u] ^ v); 87                 modify(vid[u],val[u] ^ v); 88                 val[u] = v; 89  } 90             else
91  { 92                 int fa = lca(uid[u],uid[v]); 93                 int ans = sum(uid[u]) ^ sum(uid[v]) ^ val[fa]; 94                 if(!ans)puts("-1"); 95                 else printf("%d\n",ans - 1); 96  } 97  } 98  } 99 }
HDOJ5274(參考的AC代碼)

 

6.(POJ2763)http://poj.org/problem?id=2763

題意:有一顆樹,每條邊都有本身的邊權,起點在s,有q個詢問,詢問總共有兩種操做

A:從當前點移動到x,輸出所須要的時間  B:將經過邊x的時間改成t

分析:利用RMQ計算LCA所用的,按DFS訪問的順序排列的頂點順序。這樣u到v之間的路徑就是在序列中u和v之間的全部邊減去往返重複的部分獲得的結果。只要令沿葉子方向的邊權爲正,沿根方向的部分爲負,因而有d(u,v)=d(LCA(u,v),u)+d(LCA(u,v),v)能夠用bit進行計算

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 typedef long long ll;  6 const int maxn=1e5+10;  7 int rmq[maxn*2];  8 struct ST  9 {  10     int mm[2*maxn];  11     int dp[2*maxn][20];  12     void init(int n)  13  {  14         mm[0] = -1;  15         for(int i = 1;i <= n;i++)  16  {  17             mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];  18             dp[i][0] = i;  19  }  20         for(int j = 1; j <= mm[n];j++)  21             for(int i = 1; i + (1<<j) - 1 <= n; i++)  22                 dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];  23  }  24     int query(int a,int b)  25  {  26         if(a > b)swap(a,b);  27         int k = mm[b-a+1];  28         return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];  29  }  30 };  31 
 32 struct Edge{  33     int to,nxt,w;  34 }edge[maxn*2];  35 int tot,head[maxn];  36 int F[maxn],P[maxn],cnt,n,es[maxn*2];  37 ll bit[maxn*2];  38 ST st;  39 
 40 void init()  41 {  42     tot=0;  43     memset(head,-1,sizeof(head));  44     memset(bit,0,sizeof(bit));  45 }  46 
 47 int lowbit(int x)  48 {  49     return x&(-x);  50 }  51 
 52 void add(int k,int num)  53 {  54     while ( k<=n )  55  {  56         bit[k]+=num;  57         k+=lowbit(k);  58  }  59 }  60 
 61 ll sum(int k)  62 {  63     ll sum_=0;  64     while ( k )  65  {  66         sum_+=bit[k];  67         k-=lowbit(k);  68  }  69     return sum_;  70 }  71 
 72 void addedge(int u,int v,int w)  73 {  74     edge[tot].to=v;  75     edge[tot].nxt=head[u];  76     edge[tot].w=w;  77     head[u]=tot++;  78 }  79 
 80 void dfs(int u,int pre,int dep)  81 {  82     F[++cnt]=u;  83     rmq[cnt]=dep;  84     P[u]=cnt;  85     for ( int i=head[u];i!=-1;i=edge[i].nxt )  86  {  87         int v=edge[i].to;  88         int w=edge[i].w;  89         if ( v==pre ) continue;  90         es[i]=cnt+1;  91  add(es[i],w);  92         dfs(v,u,dep+1);  93         F[++cnt]=u;  94         es[i^1]=cnt;  95         add(es[i^1],-w);  96         rmq[cnt]=dep;  97  }  98 }  99 
100 void LCA_init(int root,int num) 101 { 102     cnt=0; 103     dfs(root,root,0); 104     st.init(2*num-1); 105 } 106 
107 int query(int u,int v) 108 { 109     return F[st.query(P[u],P[v])]; 110 } 111 bool flag[maxn]; 112 
113 int main() 114 { 115     int T,N,q,s,u,v,w,op; 116     while ( scanf("%d%d%d",&N,&q,&s)!=EOF ) 117  { 118  init(); 119         n=2*N-1; 120         memset(flag,false,sizeof(flag)); 121         for ( int i=1;i<N;i++ ) 122  { 123             scanf("%d%d%d",&u,&v,&w); 124  addedge(u,v,w); 125  addedge(v,u,w); 126             flag[v]=true; 127  } 128         int root; 129         for ( int i=1;i<=N;i++ ) 130  { 131             if ( !flag[i] ) 132  { 133                 root=i; 134                 break; 135  } 136  } 137  LCA_init(root,N); 138         u=s; 139         //for ( int i=1;i<=n;i++ ) printf("%lld\n",sum(i)); 140         //for ( int i=0;i<2*(N-1);i++ ) printf("%d\n",es[i]);
141         while ( q-- ) 142  { 143             scanf("%d",&op); 144             if ( op==0 ) 145  { 146                 scanf("%d",&v); 147                 int l=query(u,v); 148                 printf("%lld\n",sum(P[u])+sum(P[v])-2*sum(P[l])); 149                 u=v; 150  } 151             else 
152  { 153                 int p,x,k1,k2; 154                 scanf("%d%d",&p,&x); 155                 k1=es[(p-1)*2]; 156                 k2=es[((p-1)*2)^1]; 157                 add(k1,x-edge[(p-1)*2].w); 158                 add(k2,edge[((p-1)*2)^1].w-x); 159                 edge[(p-1)*2].w=edge[((p-1)*2)^1].w=x; 160  } 161  } 162         //for ( int i=1;i<=n;i++ ) printf("%lld\n",sum(i));
163  } 164     return 0; 165 }
POJ2763(WA)

注:以上兩題經過與標程對拍也沒找到錯誤的點,但願有人能夠提供一下有用的數據,謝謝!

相關文章
相關標籤/搜索