For the first AA rules, it means that there should be no less than yiyi nodes painted black for the subtree of node xixi.
For the other BB rules, it means that there should be no less than yiyi nodes painted black for all nodes except the subtree of node xixi.
You need to help Bob to calculate the minimum energy he needs for the painting with all rules proposed by Alice satisfied.
InputThe first line is the number of test cases. For each test case, the first line contains one positive number N(1≤N≤100000)N(1≤N≤100000), indicating the number of trees nodes.
The following N−1N−1 lines describe the edges. Each line contains two integers u,vu,v(1≤u,v≤N1≤u,v≤N), denoting there is a edge between node uu and node vv.
The following one line contains one number AA(A≤100000A≤100000), indicating the first AArules.
The following AA lines describe the first AA rules. Each line contains two numbers xixiand yiyi as described above.
The following one line contains one number BB(B≤100000B≤100000), indicating the other BBrules.
The following BB lines describe the other BB rules. Each line contains two numbers xixiand yiyi as described above.
OutputFor each test case, output a integer donating the minimum energy Bob needs to use with all rules propose by Alice satisfied. If there is no solution, output −1−1instead.
Sample Input
2 5 1 2 2 3 3 4 1 5 2 2 1 5 1 1 2 1 5 1 2 2 3 3 4 1 5 3 1 2 2 2 5 1 1 3 5
Sample Output
2 -1
题意抽象:
给定一棵节点数为N的树,现要给节点染色,要求满足A+B条规则:
前A条规则的输入约定为一组x,y,表示编号为x的节点的子树中要有不少于y个点被染色。
后B条规则的输入也约定为一组x,y,表示编号为x的节点的子树之外要有不少于y个点被染色。
求满足条件的最少染色数。无答案返回-1.
约定输入的树的根节点序号为1.
数据规模:节点数N≤100000,边数为N-1,A≤100000,B≤100000。
模拟赛的时候没想出来。
关键在于二分答案,把子树外不少于y个节点被染色转化为子树内最多多少个点被染色。
然后dfs维护节点的子树能染色点数的区间即可,最后判断是否出现冲突以及二分的答案mid在不在根节点的子树能染色点数的区间中即可。
O(nlogn)
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;++i) using namespace std; const int MAXN=100100; int pointer[MAXN]; int n,tot,A,B,now; int low[MAXN],high[MAXN]; int RuleA[MAXN]; int RuleB[MAXN]; int cnt=0; struct Edge { int to,next; Edge() {} Edge(int b,int nxt) {to=b;next=nxt;} }edge[2*MAXN]; void init() { tot=0; memset(pointer,-1,sizeof(pointer)); memset(RuleA,0,sizeof(RuleA)); memset(RuleB,0,sizeof(RuleB)); } inline void addedge(int a,int b) { edge[tot]=Edge(b,pointer[a]); pointer[a]=tot++; edge[tot]=Edge(a,pointer[b]); pointer[b]=tot++; } void Input() { scanf("%d",&n); int u,v; rep(i,1,n-1) { scanf("%d%d",&u,&v); addedge(u,v); } scanf("%d",&A); int x,y; rep(i,1,A) { scanf("%d%d",&x,&y); RuleA[x]=max(y,RuleA[x]); } scanf("%d",&B); rep(i,1,B) { scanf("%d%d",&x,&y); RuleB[x]=max(RuleB[x],y); } } void dfs(int u,int pre) { int lowsum=0,highsum=0; low[u]=RuleA[u]; high[u]=now-RuleB[u]; for(int j=pointer[u];j!=-1;j=edge[j].next) { int v=edge[j].to; if(v==pre) continue; dfs(v,u); lowsum+=low[v]; highsum+=high[v]; } low[u]=max(low[u],lowsum); high[u]=min(high[u],highsum+1); } bool check(int k) { now=k; dfs(1,1); if(RuleB[1]>0) return 0; for(int i=1;i<=n;++i) { if(high[i]<low[i]) return 0; } if(k<=high[1]&&k>=low[1]) return 1; else return 0; } int main() { // freopen("in.txt","r",stdin); int TT;scanf("%d",&TT); rep(t1,1,TT) { init(); Input(); int l=0,r=n; while(l<r) { int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid+1; } if(!check(l)) printf("-1 "); else printf("%d ",l); } return 0; }