C. Garland----DFS

C. Garland
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Once at New Year Dima had a dream in which he was presented a fairy garland. A garland is a set of lamps, some pairs of which are connected by wires. Dima remembered that each two lamps in the garland were connected directly or indirectly via some wires. Furthermore, the number of wires was exactly one less than the number of lamps.

There was something unusual about the garland. Each lamp had its own brightness which depended on the temperature of the lamp. Temperatures could be positive, negative or zero. Dima has two friends, so he decided to share the garland with them. He wants to cut two different wires so that the garland breaks up into three parts. Each part of the garland should shine equally, i. e. the sums of lamps' temperatures should be equal in each of the parts. Of course, each of the parts should be non-empty, i. e. each part should contain at least one lamp.

Help Dima to find a suitable way to cut the garland, or determine that this is impossible.

While examining the garland, Dima lifted it up holding by one of the lamps. Thus, each of the lamps, except the one he is holding by, is now hanging on some wire. So, you should print two lamp ids as the answer which denote that Dima should cut the wires these lamps are hanging on. Of course, the lamp Dima is holding the garland by can't be included in the answer.

Input

The first line contains single integer n (3 ≤ n ≤ 106) — the number of lamps in the garland.

Then n lines follow. The i-th of them contain the information about the i-th lamp: the number lamp ai, it is hanging on (and 0, if is there is no such lamp), and its temperature ti ( - 100 ≤ ti ≤ 100). The lamps are numbered from 1 to n.

Output

If there is no solution, print -1.

Otherwise print two integers — the indexes of the lamps which mean Dima should cut the wires they are hanging on. If there are multiple answers, print any of them.

Examples
input
6
2 4
0 5
4 2
2 1
1 1
4 2
output
1 4
input
6
2 4
0 6
4 2
2 1
1 1
4 2
output
-1
Note

The garland and cuts scheme for the first example:


题目链接:http://codeforces.com/contest/767/problem/C


cf补题。

题目的意思是说给你一棵树,树的每一个点都有一个权值(点权的题可不多见),然后把所有的点权加和,我们要在sum/3的点截开,问可不可以截。

我上来暴力了一发,本以为会超时,结果出错了,wa在了第九发,少考虑了一种情况。

考虑这种情况:

5

2 1

3 2

0 3

3 0

4 3

(不知道咋了,图片弄不上来了)这样是一种截法,


也是一种截法。


但是我的代码会


这种不合理的截法,毕竟我每个点到最后记录的是此节点及其子树的权值的和。

我的错误的代码(我算的时间复杂度应超时):

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int fa[200000];
int cnt[200000];
int ans[200000];
bool flag=false;
long long sum;
void dfs(int x,int cnt){
    if(x==0)
        return ;
    ans[x]+=cnt;
    dfs(fa[x],cnt);
}
void dfs1(int x,int i){
    if(x==0)
        return ;
    if(flag)
        return ;
    if(ans[x]==sum/3*2){
        if(x>i){
            x=x^i;
            i=x^i;
            x=x^i;
        }
        printf("%d %d\n",x,i);
        flag=true;
        return ;
    }
    dfs1(fa[x],i);
}
int main(){
    memset(fa,0,sizeof(fa));
    memset(cnt,0,sizeof(cnt));
    memset(ans,0,sizeof(ans));
    int n;
    sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        fa[i]=a;
        cnt[i]=b;
        sum+=b;
    }
    if(sum%3){
        return 0*printf("-1\n");
    }
    for(int i=1;i<=n;i++){
        dfs(i,cnt[i]);
    }
    int k=0,j=0;
    for(int i=1;i<=n;i++){
        if(ans[i]==sum/3){
            k++;
            if(k==1)
                j=i;
        }
        if(k==2){
            if(j>i){
                j=j^i;
                i=j^i;
                j=j^i;
            }
            return 0*printf("%d %d\n",j,i);
        }
    }
    for(int i=1;i<=n;i++){
        if(ans[i]==sum/3){
            dfs1(i,i);
        }
    }
    if(!flag){
        return 0*printf("-1\n");
    }
    return 0;
}

然后就GG了,我看了大牛的题解,恍然大悟啊,一种情况是sum/3*2这个点是sum/3这个点的祖先,这种情况直接输出就可以,另一种情况是用vector存sum/3的点及其所有祖先节点,用set存vector里的左右祖先(并不存“叶子”),然后判断vector.size()-set.size()>=2就输出没有标记的两个点,否则无解。

大牛链接:

http://blog.csdn.net/chyllo/article/details/55803426


cf炸了,也不知道代码对不对。。。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <set>
using namespace std;
const int MAXN=1000005;
struct Edge{
    int v,w;
    Edge(int _v=0,int _w=0):v(_v),w(_w){};
};
int cnt[MAXN],fa[MAXN];
bool vis[MAXN],vis2[MAXN],vis3[MAXN];
vector<Edge> vec[MAXN];
int dfs(int x){
    int sum=0;
    for(int i=0;i<(int )vec[x].size();i++){
        cnt[vec[x][i].v]+=dfs(vec[x][i].v);
        sum+=cnt[vec[x][i].v];
    }
    return sum;
}
int ff=0,pos=-1;
void Find(int x,int f){
    if(fa[x]==x)
        return ;
    if(ff==1)
        return ;
    if(cnt[x]==f){
        pos=x;
        ff=1;
        return ;
    }
    else
        vis2[x]=1;
    if(vis2[fa[x]]==0)
        Find(fa[x],f);
}
vector<int> uu;
void f(int x){
    vis[x]=1;
    vis3[x]=1;
    if(fa[x]==x)
        return ;
    if(vis[fa[x]]==0)
        f(fa[x]);
}
int main(){
    int n;
    int a,b,root,sum=0;
    memset(cnt,0,sizeof(cnt));
    memset(vis,0,sizeof(vis));
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a,&b);
        cnt[i]+=b;
        if(a!=0){
            vec[a].push_back(Edge(i,b));
            fa[i]=a;
        }
        sum+=b;
        if(a==0){
            root=i;
            fa[i]=i;
        }
    }
    cnt[root]+=dfs(root);
    if(sum%3!=0){
        return 0*printf("-1\n");
    }
    else{
        uu.clear();
        for(int i=1;i<=n;i++){
            if(cnt[i]==sum/3){
                uu.push_back(i);
                ff=0;
                if(vis2[fa[i]]==0){
                    Find(fa[i],sum/3*2);
                }
                if(ff==1){
                    return 0*printf("%d %d\n",i,pos);
                }
            }
        }
        for(int i=0;i<(int )uu.size();i++){
            if(vis[fa[uu[i]]]==0){
                f(fa[uu[i]]);
            }
        }
        int ans[10],pppp=0;
        for(int i=0;i<(int )uu.size();i++){
            if(vis3[uu[i]]==0)
                ans[pppp++]=uu[i];
        }
        if(pppp>=2)
            printf("%d %d\n",ans[0],ans[1]);
        else
            printf("-1\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值