【SPOJ - QTREE2】树链剖分

http://acm.hust.edu.cn/vjudge/problem/19960

题意:

有一棵N个节点的树(1<=N<=10000),N-1条边,边的编号为1~N-1,每条边有一个权值,要求模拟两种操作:

1:DIST a b :求 点a到点b之间的距离

2:KTH a b k :求从a出发到b遇到的第k个节点的编号

 

QTREE系列的第二题。求dist就不用说啦,主要是求第k个。

方法一 :我是先跳了一遍,求出x到y的距离l,然后用树链剖分的跳法x走了k或者y走了l-k找到该点。很多细节。。。

方法二:先跳一遍,找到lca,然后判断k在x到lca的路上还是y到lca的路上,即是x到lca的第k个点或y到lca的第k‘个点。然后用倍增找到该点。(我觉得这个是最优的)

方法三:跳一遍找到lca后一层一层往上跳。。为什么这个方法不会超时。。TAT

 

方法一

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 const int N=10010;
  9 char s[10];
 10 struct trnode{
 11     int lc,rc,l,r,c;
 12 }t[2*N];
 13 struct node{
 14     int x,y,d,next;
 15 }a[2*N],b[N];
 16 int n,tl,z,len;
 17 int first[N],tot[N],son[N],fa[N],dep[N],ys[N],yss[N],top[N];
 18 
 19 int maxx(int x,int y){return x>y ? x:y;}
 20 
 21 void ins(int x,int y,int d)
 22 {
 23     len++;
 24     a[len].x=x;a[len].y=y;a[len].d=d;
 25     a[len].next=first[x];first[x]=len;
 26 }
 27 
 28 int build_tree(int l,int r)
 29 {
 30     int x=++tl;
 31     t[x].l=l;t[x].r=r;t[x].c=0;
 32     t[x].lc=t[x].rc=-1;
 33     if(l<r)
 34     {
 35         int mid=(l+r)>>1;
 36         t[x].lc=build_tree(l,mid);
 37         t[x].rc=build_tree(mid+1,r);
 38     }
 39     return x;
 40 }
 41 
 42 void change(int x,int p,int c)
 43 {
 44     if(t[x].l==t[x].r) {t[x].c+=c;return;}
 45     int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)>>1;
 46     if(p<=mid) change(lc,p,c);
 47     else change(rc,p,c);
 48     t[x].c=t[lc].c+t[rc].c;
 49 }
 50 
 51 int query(int x,int l,int r)
 52 {
 53     if(t[x].l==l && t[x].r==r) return t[x].c;
 54     int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)>>1;
 55     if(r<=mid) return query(lc,l,r);
 56     else if(l>mid) return query(rc,l,r);
 57     return query(lc,l,mid)+query(rc,mid+1,r);
 58 }
 59 
 60 void dfs1(int x)
 61 {
 62     tot[x]=1;son[x]=0;
 63     for(int i=first[x];i;i=a[i].next)
 64     {
 65         int y=a[i].y;
 66         if(y==fa[x]) continue;
 67         fa[y]=x;
 68         dep[y]=dep[x]+1;
 69         dfs1(y);
 70         if(tot[son[x]]<tot[y]) son[x]=y;
 71         tot[x]+=tot[y];
 72     }
 73 }
 74 
 75 void dfs2(int x,int tp)
 76 {
 77     ys[x]=++z;yss[z]=x;top[x]=tp;
 78     if(son[x]) dfs2(son[x],tp);
 79     for(int i=first[x];i;i=a[i].next)
 80     {
 81         int y=a[i].y;
 82         if(y==fa[x] || y==son[x]) continue;
 83         dfs2(y,y);
 84     }
 85 }
 86 
 87 int solve(int x,int y,int k)
 88 {
 89     int tx=top[x],ty=top[y];
 90     int ans=0,l=0,xx=x,yy=y;
 91     bool bk=0;
 92     while(tx!=ty)
 93     {
 94         if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y);
 95         if(!k) ans+=query(1,ys[ty],ys[y]);
 96         else l+=ys[y]-ys[ty]+1;
 97         y=fa[ty];ty=top[y];
 98     }
 99     
100     if(x==y) {l++;if(!k) return ans;}
101     else 
102     {
103         if(dep[x]>dep[y]) swap(x,y);
104         l+=ys[y]-ys[x]+1;
105         if(!k) return ans+query(1,ys[son[x]],ys[y]);
106     }
107 //找第k个  debug!注意细节!
108     if(k>l) return 0;
109     x=xx,y=yy;tx=top[x],ty=top[y];
110     int now1=1,now2=1,p=0;
111     if(now1==k) return x;
112     if(now2==l-k+1) return y;
113     while(tx!=ty)
114     {
115         if(dep[tx]>dep[ty]) swap(tx,ty),swap(x,y),p=1-p;
116         int ll=ys[y]-ys[ty];
117         if(p)
118         {
119             if(now1+ll>=k) return ans=yss[ys[y]-(k-now1)];
120             else now1+=ll;
121             now1++;if(now1==k) return ans=fa[ty];
122         }
123         else
124         {
125             if(now2+ll>=l-k+1) return ans=yss[ys[y]-(l-k+1-now2)];
126             else now2+=ll;
127             now2++;if(now2==l-k+1) return ans=fa[ty];
128         }
129         y=fa[ty];ty=top[y];
130     }
131     if(dep[x]>dep[y]) swap(x,y),p=1-p;
132     if(p) ans=yss[ys[y]-(k-now1)];
133     else ans=yss[ys[y]-(l-k+1-now2)];
134     return ans;
135 }
136 
137 int main()
138 {
139     freopen("a.in","r",stdin);
140     // freopen("me.out","w",stdout);
141     int T;
142     scanf("%d",&T);
143     while(T--)
144     {
145         scanf("%d",&n);
146         len=0;tl=0;z=0;dep[1]=0;tot[0]=0;
147         memset(fa,0,sizeof(fa));
148         memset(first,0,sizeof(first));
149         for(int i=1;i<n;i++)
150         {
151             scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].d);
152             ins(b[i].x,b[i].y,b[i].d);
153             ins(b[i].y,b[i].x,b[i].d);
154         }
155         dfs1(1);
156         dfs2(1,1);
157         build_tree(1,z);
158         for(int i=1;i<n;i++) if(dep[b[i].x]>dep[b[i].y]) swap(b[i].x,b[i].y);
159         for(int i=1;i<n;i++) change(1,ys[b[i].y],b[i].d);
160         while(1)
161         {
162             scanf("%s",s);
163             int x,y,k=0;
164             if((s[0]=='D' && s[1]=='I') || s[0]=='K') 
165             {
166                 scanf("%d%d",&x,&y);
167                 if(s[0]=='K') scanf("%d",&k);
168                 printf("%d\n",solve(x,y,k));
169             }
170             if(s[0]=='D' && s[1]=='O') break;
171         }
172     }
173     return 0;
174 }

方法三

  1 #include<cstdio>
  2 #include<cstring>
  3 #define maxn 11000
  4 using namespace std;
  5 struct enode{int x,y,next;}a[maxn*2];int len,last[maxn];
  6 void ins(int x,int y)
  7 {
  8     len++; a[len].x=x; a[len].y=y;
  9     a[len].next=last[x]; last[x]=len;
 10 }
 11 struct trnode{int lc,rc,l,r,c;}tr[maxn*2];int trlen;
 12 void bt(int l,int r)
 13 {
 14     int now=++trlen;
 15     tr[now].l=l; tr[now].r=r;tr[now].lc=tr[now].rc=-1;
 16     tr[now].c=0;
 17     if(l<r)
 18     {
 19         int mid=(l+r)/2;
 20         tr[now].lc=trlen+1; bt(l,mid);
 21         tr[now].rc=trlen+1; bt(mid+1,r);
 22     }
 23 }
 24 int n,fa[maxn],dep[maxn], son[maxn],tot[maxn],top[maxn];
 25 void pre_tree_node(int x)
 26 {
 27     tot[x]=1;son[x]=0;
 28     for(int k=last[x];k;k=a[k].next)
 29     {
 30         int y=a[k].y;
 31         if(y!=fa[x])
 32         {
 33             fa[y]=x;
 34 dep[y]=dep[x]+1;
 35             pre_tree_node(y);
 36             tot[x]+=tot[y];
 37             if(tot[son[x]]<tot[y]) son[x]=y;
 38         }
 39     }
 40 }
 41 
 42 int z,ys[maxn];
 43 void pre_tree_edge(int x,int tp)
 44 {
 45     ys[x]=++z;top[x]=tp;
 46     if(son[x]!=0)pre_tree_edge(son[x],tp);
 47     for(int k=last[x];k;k=a[k].next)
 48     {
 49         int y=a[k].y;
 50         if(y!=fa[x]&& y!=son[x]) pre_tree_edge(y,y);
 51     }
 52 }
 53 
 54 void change(int now,int p,int c)
 55 {
 56     if( tr[now].l==tr[now].r) { tr[now].c=c; return ;}
 57     int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
 58     if(p<=mid) change(lc,p,c);  else change(rc,p,c);
 59     tr[now].c=tr[lc].c+tr[rc].c;
 60 }
 61 int  findsum(int now,int l,int r)//findsum的功能就是求新编号为l的边到新编号为r的边的总和(连续)
 62 {
 63     if( l==tr[now].l && tr[now].r==r) return tr[now].c;
 64     int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
 65     if(mid<l)       return findsum(rc,l,r);
 66     else if(r<=mid) return findsum(lc,l,r);
 67     else            return findsum(lc,l,mid)+findsum(rc,mid+1,r);
 68 }
 69 
 70 
 71 int  solve(int x,int y)
 72 {
 73     int tx=top[x],ty=top[y],ans=0;
 74     while(tx!=ty)
 75     {
 76         if(dep[tx]>dep[ty]){ int t=tx;tx=ty;ty=t; t=x;x=y;y=t;}
 77         ans+= findsum(1,ys[ty],ys[y]);
 78         y=fa[ty];ty=top[y];
 79     }
 80     if(x==y) return ans;
 81     else
 82     {
 83         if(dep[x]>dep[y]){ int t=x;x=y;y=t;}
 84         return ans+ findsum(1,ys[son[x]],ys[y]);
 85     }
 86 }
 87 
 88 int listx[maxn],listy[maxn];   //x一层层往上跳,经过的点保存在listx数组中
 89                                //y一层层往上跳,经过的点保存在listy数组中
 90 int  findKth(int x,int y,int K)//求从x点出发到y点,一路上遇到的第K个点是谁
 91 { //总体思路就是x和y一层层往上跳,比solve好理解啊。
 92     int lx=0,ly=0,fx,fy;
 93     while(x!=y)//如果x和y没有相遇
 94     {
 95         if(dep[x]>dep[y]){ listx[++lx]=x;x=fa[x];}//这里决定谁往上跳,为什么是不比tx和ty?
 96         else { listy[++ly]=y;y=fa[y];}
 97         
 98         if(lx==K) return listx[lx];  //如果提前遇到第K个就直接结束了
 99     }
100     listx[++lx]=x; // 此时x==y,随便listx或者listy都可以保存
101     
102     if(K<=lx)  return listx[K];
103     else       return listy[ ly - (K-lx)+1  ];
104 }
105 struct bian{int x,y,c;}e[maxn];
106 int main()
107 {
108     int i,tt,x,y,c,p,K; scanf("%d",&tt);
109     while(tt--)
110     {
111         scanf("%d",&n);
112         len=0;memset(last,0,sizeof(last));
113         for(i=1;i<n;i++)
114         {
115             scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].c);
116             ins(e[i].x,e[i].y);
117             ins(e[i].y,e[i].x);
118         }
119         
120         dep[1]=fa[1]=0; pre_tree_node(1);
121         
122         z=0; pre_tree_edge(1,1);
123         
124         trlen=0;bt(1,z);
125         
126         for(i=1;i<n;i++)    if( dep[e[i].x]>dep[e[i].y]){ int t=e[i].x;e[i].x=e[i].y;e[i].y=t;}
127         for(i=1;i<n;i++)    change(1,ys[ e[i].y ], e[i].c);
128         
129         char ss[20];
130         while( scanf("%s",ss)!=EOF)
131         {
132             if(ss[1]=='O') break;
133             if(ss[1]=='I'){scanf("%d%d",&x,&y); printf("%d\n",solve(x,y));}
134              else{ scanf("%d%d%d",&x,&y,&K); printf("%d\n",findKth(x,y,K));}
135         }
136         
137     }
138     return 0;
139 }

 

posted @ 2016-08-07 16:47  拦路雨偏似雪花  阅读(257)  评论(0编辑  收藏  举报