equation

equation

题目描述

 

有一棵n 个点的以 1 为根的树, 以及 n 个整数变量xi。树上 i 的父亲是 fi, 每条边(i,fi)有一个权值wi,表示一个方程 xi + xfi = wi,这 n-1个方程构成了一个方程组。

现在给出q 个操作,有两种类型:

1 u v s,表示询问加上 xu + xv = s 这个方程后,整个方程组的解的情况。具体来说, 如果方程有唯一解, 输出此时 x1 的值; 如果有无限多个解,输出 inf;如果无解,输出 none. 注意每个询问是独立的。

2 u w,表示将 wu 修改为 w。


solution

首先我们把所有点的权值写成W+x1 或W-x1的样子。

那么每次询问就相当于挑两个点解方程。

现在剩下修改。

修改一个点,它对自己子树的贡献按深度为+1 -1 +1…

一开始先dfs

对于每一个点记一个op为 +1 -1

统计时乘上系数即可。

由于是区间修改,单点查询,可以ccj线段树或差分再树状数组实现

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define maxn 1000005
#define ll long long
using namespace std;
int n,q,OP,head[maxn],f[maxn],w[maxn],tot;
int dfst[maxn],dfsn[maxn],sc,op[maxn],val[maxn];
int t1,t2,t3,li,ri,dy[maxn];
struct node{
    int v,nex;
}e[maxn];
struct no{
    ll v;
}tree[maxn*8];
void lj(int t1,int t2){
    e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,int opt){
    dfst[k]=++sc;op[k]=opt;dy[sc]=k;
    for(int i=head[k];i;i=e[i].nex){
        val[e[i].v]=-val[k]+w[e[i].v];
        dfs(e[i].v,-opt);
    }
    dfsn[k]=sc;
}
void build(int k,int L,int R){
    if(L==R){
        tree[k].v=op[dy[L]]*val[dy[L]];return;
    }
    int mid=L+R>>1;
    build(k*2,L,mid);build(k*2+1,mid+1,R);
}
void ch(int k,int v,int l,int r){
     
    if(l>=li&&r<=ri){
        tree[k].v+=v;
        //cout<<"change "<<tree[k].l<<' '<<tree[k].r<<' '<<tree[k].v<<endl;
        return;
    }
    int mid=l+r>>1;
    if(li<=mid)ch(k*2,v,l,mid);
    if(ri>mid)ch(k*2+1,v,mid+1,r);
}
ll ask(int k,int pl,int opt,ll now,int l,int r){
    now+=opt*tree[k].v;
    if(l==r)return now;
    //cout<<tree[k].l<<' '<<tree[k].r<<' '<<now<<endl; 
    int mid=l+r>>1;
    if(pl<=mid)return ask(k*2,pl,opt,now,l,mid);
    else return ask(k*2+1,pl,opt,now,mid+1,r);
}
int get(){
    int v=0;char ch;
    while(!isdigit(ch=getchar()));v=v+ch-48;
    while(isdigit(ch=getchar()))v=(v<<3)+(v<<1)+ch-48;
    return v;
}
int main()
{
    cin>>n>>q;
    for(int i=2;i<=n;i++){
        scanf("%d%d",&f[i],&w[i]);
        lj(f[i],i);
    }
    dfs(1,1);build(1,1,n);
    //for(int i=1;i<=n;i++)cout<<i<<' '<<val[i]<<' '<<op[i]<<endl;
    for(int i=1;i<=q;i++){
        scanf("%d",&OP);
        if(OP==1){
            scanf("%d%d%d",&t1,&t2,&t3);
            ll v1=ask(1,dfst[t1],op[t1],0,1,n),v2=ask(1,dfst[t2],op[t2],0,1,n);
            if(op[t1]+op[t2]==0){
                if(v1+v2==t3)puts("inf");
                else puts("none");
            }
            else {
                ll tmp=t3-v1-v2;
                if(tmp%2==0)printf("%lld
",tmp/2*op[t1]);
                else puts("none");
            }
        }
        else {
            scanf("%d%d",&t1,&t2);
            li=dfst[t1],ri=dfsn[t1];
            ch(1,-op[t1]*w[t1],1,n);w[t1]=t2;
            ch(1,op[t1]*w[t1],1,n);
        }
    }
    return 0;
}

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注