equation

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\n",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;
}

 

posted @ 2018-11-08 08:11 liankewei 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
从任何地方以最快,最简单,最可靠的方式远程访问您的计算机。一处访问您所有的应用程序,文件和计算机。 24/7全天候访问您的应用程序和文件。因为意外的事情总是发生。 轻按一下您的移动设备,即可可靠地连接至计算机。或通过浏览器和安全的Parallels帐户从任何其他计算机上访问它。轻松浏览硬盘驱动器以查找文件或照片,然后点击以复制或打开它。 在移动设备上的精彩体验-不再需要手指体操。 我们独特的Applification™技术可让您使用所有桌面应用程序,就像它们是iPhone,iPad或Android设备的本机应用程序一样。我们的Lock'n'Go放大镜是一个奇迹:精确地选择,复制和粘贴文本。轻触桌面上的一个小按钮或用自然的单指锁拖动图片很容易。 将所有文件放在设备上的一个位置。 使用Parallels Access Universal File Manager管理和访问云,远程计算机和本地设备上的所有文件。只需单击一下,即可将其复制并粘贴到您的移动设备(或在远程桌面上打开云文件)。 不要紧张你的眼睛。实际上,根本不要紧张! 通过在设备上全屏查看应用程序来休息一下。并让您高枕无忧,因为Parallels Access可以随时随地(即使在3G网络上)将您可靠地连接到桌面。 您的桌面应用程序仅需轻按。 轻按一下即可打开或切换应用程序。将您喜欢的桌面应用程序添加到Android设备的主屏幕,然后使用完整的桌面样式键盘来利用其所有功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值