hdu6110:路径交

$n \leq 500000$的树给$m \leq 500000$个路径,$q \leq 500000$个询问每次问一个区间的路径交。

路径交口诀:(前方高能)

判有交,此链有彼祖;

取其交,最深两两祖。

说成人话就是:判两条路径有没有交,只要一条链的lca在另一条链上就一定有交;取两条路径的交,把两条路径的端点两两求出四对lca,最深那两个就是路径交。

证明?我会还用口诀!

由于需要很多很多次查lca,这里用欧拉序+st表求。查区间路径交可以线段树也可以st表,毕竟重复的部分算两次没问题。

  1 //#include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 //#include<time.h>
  6 //#include<complex>
  7 #include<algorithm>
  8 #include<stdlib.h>
  9 using namespace std;
 10 
 11 int n,m,q;
 12 #define maxn 500011
 13 struct Edge{int to,next,v;}edge[maxn<<1]; int first[maxn],le=2;
 14 void in(int x,int y,int v) {Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;}
 15 void insert(int x,int y,int v) {in(x,y,v); in(y,x,v);}
 16 
 17 int len,dep[maxn],id[maxn],st[maxn<<1][22],Log[maxn<<1];
 18 #define LL long long
 19 LL dis[maxn];
 20 void dfs(int x,int fa)
 21 {
 22     st[++len][0]=x; id[x]=len; dep[x]=dep[fa]+1;
 23     for (int i=first[x];i;i=edge[i].next)
 24     {
 25         Edge &e=edge[i]; if (e.to==fa) continue;
 26         dis[e.to]=dis[x]+e.v; dfs(e.to,x); st[++len][0]=x;
 27     }
 28 }
 29 
 30 void makest()
 31 {
 32     Log[0]=-1; for (int i=1;i<=len;i++) Log[i]=Log[i>>1]+1;
 33     for (int j=1;j<=20;j++)
 34         for (int i=1,to=len-(1<<j)+1;i<=to;i++)
 35             st[i][j]=dep[st[i][j-1]]<dep[st[i+(1<<(j-1))][j-1]]?st[i][j-1]:st[i+(1<<(j-1))][j-1];
 36 }
 37 
 38 int lca(int x,int y)
 39 {
 40     if (id[x]>id[y]) {int t=x;x=y;y=t;} x=id[x]; y=id[y];
 41     int l=Log[y-x+1];
 42     return dep[st[x][l]]<dep[st[y-(1<<l)+1][l]]?st[x][l]:st[y-(1<<l)+1][l];
 43 }
 44 
 45 struct Line{int x,y;}line[maxn];
 46 bool cmpdep(const int a,const int b) {return dep[a]<dep[b];} 
 47 Line combine(Line a,Line b)
 48 {
 49     if (a.x==-1 || b.x==-1) return (Line){-1,-1};
 50     int l1=lca(a.x,a.y),l2=lca(b.x,b.y);
 51     int t1=lca(l1,b.x),t2=lca(l1,b.y),t3=lca(a.x,l2),t4=lca(a.y,l2);
 52     bool flag=0;
 53     if ((t1==l1 && dep[t1]>=dep[l2]) || (t2==l1 && dep[t2]>=dep[l2])) flag=1;
 54     if ((t3==l2 && dep[t3]>=dep[l1]) || (t4==l2 && dep[t4]>=dep[l1])) flag=1;
 55     if (!flag) return (Line){-1,-1};
 56     int d[5]; d[0]=lca(a.x,b.x); d[1]=lca(a.x,b.y); d[2]=lca(a.y,b.x); d[3]=lca(a.y,b.y);
 57     sort(d,d+4,cmpdep); return (Line){d[2],d[3]};
 58 }
 59 
 60 struct SMT
 61 {
 62     struct Node
 63     {
 64         int ls,rs;
 65         Line com;
 66     }a[maxn<<1];
 67     int size,n;
 68     void clear(int m) {size=0; n=m;}
 69     void up(int x)
 70     {
 71         int &p=a[x].ls,&q=a[x].rs;
 72         a[x].com=combine(a[p].com,a[q].com);
 73     }
 74     void build(int &x,int L,int R)
 75     {
 76         x=++size;
 77         if (L==R) {a[x].com=line[L]; a[x].ls=a[x].rs=0; return;}
 78         int mid=(L+R)>>1;
 79         build(a[x].ls,L,mid); build(a[x].rs,mid+1,R); up(x);
 80     }
 81     void build() {int x; build(x,1,n);}
 82     int ql,qr;
 83     Line Query(int x,int L,int R)
 84     {
 85         if (ql<=L && R<=qr) return a[x].com;
 86         int mid=(L+R)>>1; Line ans; bool flag=0;
 87         if (ql<=mid) ans=Query(a[x].ls,L,mid),flag=1;
 88         if (qr>mid) {if (flag) ans=combine(Query(a[x].rs,mid+1,R),ans); else ans=Query(a[x].rs,mid+1,R);}
 89         return ans;
 90     }
 91     Line query(int L,int R) {ql=L; qr=R; return Query(1,1,n);}
 92 }t;
 93 
 94 int main()
 95 {
 96     scanf("%d",&n);
 97     for (int i=1,x,y,v;i<n;i++) scanf("%d%d%d",&x,&y,&v),insert(x,y,v);
 98     len=0; dfs(1,0); makest();
 99     scanf("%d",&m);
100     for (int i=1;i<=m;i++) scanf("%d%d",&line[i].x,&line[i].y);
101     t.clear(m); t.build();
102     scanf("%d",&q);
103     while (q--)
104     {
105         int x,y; scanf("%d%d",&x,&y);
106         Line ans=t.query(x,y);
107         printf("%lld\n",dis[ans.x]+dis[ans.y]-2*dis[lca(ans.x,ans.y)]);
108     }
109     return 0;
110 }
View Code

 

posted @ 2018-03-14 07:38  Blue233333  阅读(302)  评论(0)    收藏  举报