EZOJ #79

传送门

分析

在经过若干次操作之后一定会产生一堆环

而我们又发现从一个点到另一个点实际可以经过所有环

于是问题就转换成了$k_1s_1 + k_2s_2 + ... + len = t$

其中$s_i$为每个环的长度,$len$为两点间距离

于是每次gcd求一下就行了

注意两点间距离不用求LCA,用深度值减一下就可以了

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
long long d[100100];
vector<pair<int,int> >v[100100];
inline void dfs(int x,int fa){
    long long i,j,k;
    for(i=0;i<v[x].size();i++){
      int y=v[x][i].first,z=v[x][i].second;
      if(y==fa)continue;
      d[y]=d[x]+z;
      dfs(y,x);
    }
    return;
}
inline long long gcd(long long x,long long y){return y==0?x:gcd(y,x%y);}
int main(){
    int n,m,i,j,k;
    long long res=-1;
    scanf("%d%d",&n,&m);
    for(i=1;i<n;i++){
      int x,y;
      int z;
      scanf("%d%d%d",&x,&y,&z);
      v[x].push_back(make_pair(y,z));
      v[y].push_back(make_pair(x,-z));
    }
    d[1]=0;
    dfs(1,0);
    for(i=1;i<=m;i++){
      int x,y;
      int z;
      scanf("%d",&k);
      scanf("%d%d%d",&x,&y,&z);
      if(k==0){
          long long t=d[x]-d[y]+z;
          if(res==-1){
            res=abs(t);
        }else {
          res=gcd(res,abs(t));
        }
      }else {
          long long t=d[y]-d[x]-z;
          if(res!=-1){
            if(abs(t)%res==0)puts("yes");
              else puts("no");
          }else {
            if(t==0)puts("yes");
             else puts("no");    
        }
      }
    }
    return 0;
}
posted @ 2018-11-03 20:14  水题收割者  阅读(135)  评论(0编辑  收藏  举报