BZOJ 4326 树链剖分+二分+差分+记忆化

Posted on 2016-05-19 18:14  yyjxx2010xyu  阅读(161)  评论(0编辑  收藏  举报

去年NOIP的时候我还不会树链剖分!

还是被UOJ 的数据卡了一组。

差分的思想还是很神啊!

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <ctime>
  6 #include <cstdlib>
  7 using namespace std;
  8 const int Maxn=300100;
  9 const int Inf=0x3f3f3f3f;
 10 int n,m,u,v,w,cnt,tot,MaxLen,MinLen,Minw,Maxw,Ans;
 11 int head[Maxn],dep[Maxn],siz[Maxn],father[Maxn],W[Maxn],p[Maxn],q[Maxn],dis[Maxn],Len[Maxn],c[Maxn],top[Maxn],Memory[Maxn],Root;
 12 struct Edge{int to,next,w;}edge[Maxn<<1];
 13 inline void Get_Int(int &x)
 14 {
 15     x=0;  char ch=getchar(); int f=1;
 16     while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
 17     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} x*=f;
 18 }
 19 inline void Put_Int(int x)
 20 {
 21     char ch[20];  int top=0;
 22     if (x==0) ch[++top]='0';
 23     while (x) ch[++top]=x%10+'0',x/=10;
 24     while (top) putchar(ch[top--]); putchar('\n');
 25 }
 26 inline int Max(int x,int y) {return x>y?x:y;}
 27 inline int Min(int x,int y) {return x>y?y:x;}
 28 inline void Add(int u,int v,int w)
 29 {edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w;head[u]=cnt++;}
 30 //==============================================
 31 void Dfs1(int u,int fa)
 32 {
 33     siz[u]=1;
 34     for (int i=head[u];i!=-1;i=edge[i].next)
 35         if (edge[i].to!=fa)
 36         {
 37             dep[edge[i].to]=dep[u]+1;
 38             father[edge[i].to]=u;
 39             dis[edge[i].to]=dis[u]+edge[i].w;
 40             W[edge[i].to]=edge[i].w;
 41             Dfs1(edge[i].to,u);
 42             siz[u]+=siz[edge[i].to];
 43         }
 44 }
 45 void Dfs2(int u,int chain,int fa)
 46 {
 47     top[u]=chain;  int k=0;
 48     for (int i=head[u];i!=-1;i=edge[i].next)
 49         if (edge[i].to!=fa && (siz[edge[i].to]>siz[k] || k==0)) k=edge[i].to;
 50     if (k==0) return;
 51     Dfs2(k,chain,u);
 52     for (int i=head[u];i!=-1;i=edge[i].next)
 53         if (edge[i].to!=fa && k!=edge[i].to) Dfs2(edge[i].to,edge[i].to,u);
 54 }
 55 inline int Lca(int u,int v)
 56 {
 57     while (true)
 58     {
 59         if (top[u]==top[v]) return dep[u]>dep[v]?v:u;
 60         if (dep[top[u]]>dep[top[v]]) u=father[top[u]]; else v=father[top[v]];
 61     }
 62 }
 63 int Get(int u,int f)
 64 {
 65     for (int i=head[u];i!=-1;i=edge[i].next)
 66         if (f!=edge[i].to)
 67             c[u]+=Get(edge[i].to,u);
 68     if (c[u]==tot) MinLen=Max(MinLen,W[u]);
 69     return c[u];
 70 }
 71 inline bool Check(int t)
 72 {
 73     MaxLen=MinLen=tot=0;
 74     memset(c,0,sizeof(c));
 75     for (int i=1;i<=m;i++)
 76         if (Len[i]>t)
 77         {
 78             c[p[i]]++,c[q[i]]++;
 79             c[Lca(p[i],q[i])]-=2;
 80             MaxLen=Max(MaxLen,Len[i]);
 81             tot++;
 82         }
 83     if (Memory[tot])
 84     {
 85         if (Memory[tot]<=t) return true;
 86         return false;
 87     }
 88     Get(Root,Root);
 89     Memory[tot]=(MaxLen-MinLen);
 90     if (Memory[tot]<=t) return true;
 91     return false;
 92 }
 93 int main()
 94 {
 95     srand(time(0));
 96     Get_Int(n),Get_Int(m);
 97     memset(head,-1,sizeof(head)); Minw=Inf;
 98     for (int i=1;i<n;i++)
 99     {
100         Get_Int(u),Get_Int(v),Get_Int(w);
101         Add(u,v,w),Add(v,u,w);
102         Minw=Min(Minw,w);
103     }
104     for (int i=1;i<=m;i++) Get_Int(p[i]),Get_Int(q[i]);
105     Root=rand()%n+1;
106     father[Root]=Root; dep[Root]=1; dis[Root]=0;
107     Dfs1(Root,Root);
108     Dfs2(Root,Root,Root);
109     memset(Memory,0,sizeof(Memory));
110     for (int i=1;i<=m;i++) Len[i]=dis[p[i]]+dis[q[i]]-2*dis[Lca(p[i],q[i])],Maxw=Max(Maxw,Len[i]);
111     int l=Minw,r=Maxw;
112     while (l<=r)
113     {
114         int mid=(l+r)>>1;
115         if (Check(mid)) Ans=mid,r=mid-1; else l=mid+1;
116         
117     }
118     Put_Int(Ans);
119     return 0;
120 }
C++