zoukankan      html  css  js  c++  java
  • 洛谷 P1600 天天爱跑步(LCA+乱搞)

    传送门

    我们把每一条路径拆成$u->lca$和$lca->v$的路径

    先考虑$u->lca$,如果这条路径会对路径上的某一个点产生贡献,那么满足$dep[u]-dep[x]=w[x],dep[u]=dep[x]+w[x]$,注意到$dep[x]+w[x]$是一个定值,所以我们只要去找它的子树里有多少个点的$dep$等于$dep[x]+w[x]$就可以了,这个可以直接开一个桶。然而如果点$x$在$lca$的上面,这一条路径是不会对他产生贡献的,那么我们就得在$lca$处把这一条路径的贡献给减去。具体怎么做呢?我们可以利用树上差分的思想,在点$u$把它的出现次数$+1$,在$lca$处把它的出现次数$-1$,那么我们对于每一个点,只要去查询它的子树里$dep[x]+w[x]$这个值出现了多少次就可以了。

    顺便注意一下,因为我们的桶里存的不止是一棵子树的答案,所以查询得到的次数可能是来子其他子树的。那么我们可以dfs进去之前先记录一下,完了之后再记录一下,两次的差就是这个值在其子树里的实际出现次数

    然后$lca->v$的路径咋搞嘞?只要把式子改成$dep[v]-dep[x]=len-w[i]$($len$表示路径长度),然后和上面一样的做法。注意这里有可能会出现负数,所以我们要让它加上$3e5$

    注意到$lca$会被我们统计两次,那么我们只要最后做完之后,把所有被统计了两次答案的$lca$答案减一就好了

      1 //minamoto
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<algorithm>
      5 #include<vector>
      6 using namespace std;
      7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
      8 char buf[1<<21],*p1=buf,*p2=buf;
      9 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
     10 inline int read(){
     11     #define num ch-'0'
     12     char ch;bool flag=0;int res;
     13     while(!isdigit(ch=getc()))
     14     (ch=='-')&&(flag=true);
     15     for(res=num;isdigit(ch=getc());res=res*10+num);
     16     (flag)&&(res=-res);
     17     #undef num
     18     return res;
     19 }
     20 char sr[1<<21],z[20];int C=-1,Z;
     21 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
     22 inline void print(int x){
     23     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
     24     while(z[++Z]=x%10+48,x/=10);
     25     while(sr[++C]=z[Z],--Z);sr[++C]=' ';
     26 }
     27 const int N=300005,M=600005;
     28 int head[N],Next[M],ver[M],tot;
     29 int son[N],sz[N],fa[N],dep[N],top[N];
     30 int c[N],w[N],val[N],num[1000005];
     31 int n,m,lim,ans[N];
     32 vector<int> qaq[N],qaq2[N],qaq3[N];
     33 struct node{int s,t,lca,len;}q[N];
     34 inline void add(int u,int v){
     35     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
     36     ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
     37 }
     38 void dfs1(int u){
     39     sz[u]=1,dep[u]=dep[fa[u]]+1,cmax(lim,dep[u]);
     40     for(int i=head[u];i;i=Next[i]){
     41         int v=ver[i];
     42         if(v!=fa[u]){
     43             fa[v]=u,dfs1(v),sz[u]+=sz[v];
     44             if(sz[v]>sz[son[u]]) son[u]=v;
     45         }
     46     }
     47 }
     48 void dfs2(int u,int t){
     49     top[u]=t;
     50     if(son[u]) dfs2(son[u],t);else return;
     51     for(int i=head[u];i;i=Next[i]){
     52         int v=ver[i];
     53         if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
     54     }
     55 }
     56 inline int LCA(int u,int v){
     57     while(top[u]!=top[v]){
     58         if(dep[top[u]]<dep[top[v]]) swap(u,v);u=fa[top[u]];
     59     }
     60     return dep[u]<dep[v]?u:v;
     61 }
     62 void dfs(int u,int fa){
     63     int now=w[u]+dep[u],k;if(now<=lim) k=c[now];
     64     for(int i=head[u];i;i=Next[i]){
     65         int v=ver[i];if(v!=fa) dfs(v,u);
     66     }
     67     c[dep[u]]+=val[u];if(now<=lim) ans[u]=c[now]-k;
     68     for(int i=0,s=qaq[u].size();i<s;++i) --c[dep[qaq[u][i]]];
     69 }
     70 void DFS(int u,int fa){
     71     int now=dep[u]-w[u],k;now+=300000,k=num[now];
     72     for(int i=head[u];i;i=Next[i]){
     73         int v=ver[i];if(v!=fa) DFS(v,u);
     74     }
     75     for(int i=0,s=qaq2[u].size();i<s;++i) ++num[300000+qaq2[u][i]];
     76     ans[u]+=num[now]-k;
     77     for(int i=0,s=qaq3[u].size();i<s;++i) --num[300000+qaq3[u][i]];
     78 }
     79 int main(){
     80     //freopen("testdata.in","r",stdin);
     81     n=read(),m=read();
     82     for(int i=1;i<n;++i){
     83         int u=read(),v=read();add(u,v);
     84     }
     85     for(int i=1;i<=n;++i) w[i]=read();
     86     dfs1(1),dfs2(1,1);
     87     for(int i=1;i<=m;++i){
     88         q[i].s=read(),q[i].t=read(),++val[q[i].s];
     89         q[i].lca=LCA(q[i].s,q[i].t),q[i].len=dep[q[i].s]+dep[q[i].t]-dep[q[i].lca]*2;
     90         qaq[q[i].lca].push_back(q[i].s);
     91     }
     92     dfs(1,0);
     93     for(int i=1;i<=m;++i){
     94         qaq2[q[i].t].push_back(dep[q[i].t]-q[i].len);
     95         qaq3[q[i].lca].push_back(dep[q[i].t]-q[i].len);
     96     }
     97     DFS(1,0);
     98     for(int i=1;i<=m;++i) if(dep[q[i].s]-dep[q[i].lca]==w[q[i].lca]) --ans[q[i].lca];
     99     for(int i=1;i<=n;++i) print(ans[i]);
    100     Ot();
    101     return 0;
    102 }
  • 相关阅读:
    C# 异步编程 (12)
    C# 动态语言扩展(11)
    C# LINQ(10)
    代码整洁之道(1)
    C# 集合(9) 持续更新
    C# 字符串和正则表达式(8) 持续更新
    C# 委托、lambda表达式和事件 (7) 持续更新
    C# 运算符和类型强制转换(6) 持续更新
    C++_将图二维矩阵形式转为邻接表结构
    .NET(C#)连接各类数据库-集锦
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9563834.html
Copyright © 2011-2022 走看看