http://codeforces.com/problemset/problem/1296/F
题意:
一棵树,边权,给出很多条路径的信息(路径上的最小值),求一个合法的树
解析:
最小值为X相当于全部大于等于X。所以树链剖分,区间取最大值即可。
判断不存在:
按照每条边当前权值重新建树,求区间最小值。如果和之前的区间最小值不一样就是-1。(例如[1,4]=2,[1,2]=3,[2,4]=5,显然不成立)
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<limits.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define root int rt,int l,int r
#define lson ls,l,mid
#define rson rs,mid+1,r
const int maxn=1e4+4;
int n;
int v[maxn];//点权
int head[maxn],nex[maxn<<1],val[maxn<<1],to[maxn<<1],now;
int fa[maxn],dep[maxn],siz[maxn],son[maxn];
int pointid(int edge){
int p1=to[(edge<<1)-1];// 链式前向星存图
int p2=to[edge<<1];
int p=p1;
if(dep[p2]>dep[p1])p=p2;
return p;
}
inline void add(int a,int b,int v){
nex[++now]=head[a];head[a]=now;to[now]=b;val[now]=v;
}
//************************************************
int w[maxn];//线段树基础数组
int tr[maxn<<2];//线段树
int lz[maxn<<2];
void build(int rt,int l,int r){
if(l==r){tr[rt]=w[l];lz[rt]=0;return;}
build(lson);
build(rson);
tr[rt]=max(tr[ls],tr[rs]);
}
void pushdown(int rt){
if(lz[rt]){
tr[ls]=max(tr[ls],lz[rt]);
tr[rs]=max(tr[rs],lz[rt]);
lz[ls]=max(lz[ls],lz[rt]);
lz[rs]=max(lz[rs],lz[rt]);
lz[rt]=0;
}
}
void update(root,int L,int R,int val){
if(l>=L&&r<=R){
tr[rt]=max(tr[rt],val);
lz[rt]=max(lz[rt],val);
return ;
}
pushdown(rt);
if(L<=mid)update(lson,L,R,val);
if(R>mid)update(rson,L,R,val);
tr[rt]=max(tr[ls],tr[rs]);
}
int query(root,int L,int R){
if(l>=L&&r<=R){
return tr[rt];
}
pushdown(rt);
int ans=-2e9;
if(L<=mid)ans=max(ans,query(lson,L,R));
if(R>mid)ans=max(ans,query(rson,L,R));
return ans;
}
//************************************************
// 跑出树的信息
void dfs_init(int p,int f,int deep){
fa[p]=f;
dep[p]=deep;
siz[p]=1;
son[p]=0;
int maxx=-1;
for(register int i=head[p];i;i=nex[i]){
int uv=to[i];
if(uv==f)continue;
v[uv]=val[i];//边权转点权
dfs_init(uv,p,deep+1);
siz[p]+=siz[uv];
if(siz[uv]>maxx){
maxx=siz[uv];
son[p]=uv;
}
}
}
// 跑出对应dfs序
int top[maxn],id[maxn];
int cnt;
void dfs(int p,int rt){
top[p]=rt;
id[p]=++cnt;
w[cnt]=v[p];
if(!son[p])return;
// 先跑重儿子
dfs(son[p],rt);
for(register int i=head[p];i;i=nex[i]){
int uv=to[i];
if(uv==fa[p]||uv==son[p])continue;
dfs(uv,uv); // 不是重儿子开新链
}
}
//树操作转线段树操作
void Update(int s,int t,int val){
while(top[s]!=top[t]){
if(dep[top[s]]>dep[top[t]])swap(s,t);
update(1,1,n,id[top[t]],id[t],val);
t=fa[top[t]];
}
if(s==t)return ;
if(dep[s]>dep[t])swap(s,t);
update(1,1,n,id[s]+1,id[t],val);
}
int Query(int s,int t){
int ans=-2e9;
if(s==t)return ans;
while(top[s]!=top[t]){
if(dep[top[s]]>dep[top[t]])swap(s,t);
ans=max(ans,query(1,1,n,id[top[t]],id[t]));
t=fa[top[t]];
}
if(s==t)return ans;
if(dep[s]>dep[t])swap(s,t);
ans=max(ans,query(1,1,n,id[s]+1,id[t]));
return ans;
}
void init(){
memset(head,0,sizeof(head));
now=cnt=0;
memset(lz,0,sizeof lz);
}
int A[maxn],B[maxn];
void Build_Min(root){
if(l==r){
return;
}
pushdown(rt);
Build_Min(lson);
Build_Min(rson);
tr[rt]=min(tr[ls],tr[rs]);
}
int query_Min(root,int L,int R){
if(l>=L&&r<=R){
return tr[rt];
}
int ans=2e9;
if(L<=mid)ans=query_Min(lson,L,R);
if(R>mid)ans=min(ans,query_Min(rson,L,R));
return ans;
}
int Query_Min(int s,int t){
int ans=2e9;
if(s==t)return ans;
while(top[s]!=top[t]){
if(dep[top[s]]>dep[top[t]])swap(s,t);
ans=min(ans,query_Min(1,1,n,id[top[t]],id[t]));
t=fa[top[t]];
}
if(s==t)return ans;
if(dep[s]>dep[t])swap(s,t);
ans=min(ans,query_Min(1,1,n,id[s]+1,id[t]));
return ans;
}
struct node{
int a,b,v;
}Q[maxn];
int Ans[maxn];
int main(){
scanf("%d",&n);
rep(i,1,n-1){
scanf("%d%d",A+i,B+i);
add(A[i],B[i],0);
add(B[i],A[i],0);
}
int rt=1;
v[rt]=0;
dfs_init(rt,-1,1);
dfs(rt,rt);
build(1,1,n);
int q;scanf("%d",&q);
rep(i,1,q){
int a,b,v;scanf("%d%d%d",&a,&b,&v);
Update(a,b,v);
Q[i].a=a;
Q[i].b=b;
Q[i].v=v;
}
rep(i,1,n-1){
Ans[i]=Query(A[i],B[i]);
}
Build_Min(1,1,n);
rep(i,1,q){
int res=Query_Min(Q[i].a,Q[i].b);
if(Q[i].v!=res)return 0*printf("-1\n");
}
rep(i,1,n-1)printf("%d%c",max(1,Ans[i])," \n"[i==n-1]);
}