[bzoj4151][AMPPZ2014]The Cave

来自FallDream的博客,未经允许,请勿转载,谢谢。


给定一棵有n个节点的树,相邻两点之间的距离为1。
请找到一个点x,使其满足所有m条限制,其中第i条限制为dist(x,a[i])+dist(x,b[i])<=d[i]。
n<=300000,m<=300000
 
一个点如果满足题意,那么他和点1的距离至少为$max(0,\frac{ai+bi-di}{2})$
找出最大的那个点。如果有解,那么那个点肯定可以。暴力判断行不行就可以了。
#include<iostream>
#include<cstdio>
#define MN 300000
#define getchar() (*S++)
char B[1<<26],*S=B;
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9')  ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}
int head[MN+5],n,m,cnt=0,dep[MN+5],a[MN+5],fa[MN+5],b[MN+5],d[MN+5];
struct edge{int to,next;}e[MN*2+5];
inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;
}

void Dfs(int x,int f)
{
    fa[x]=f;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f)
            dep[e[i].to]=dep[x]+1,Dfs(e[i].to,x);    
}

int main()
{
    fread(B,1,1<<26,stdin); 
    for(int T=read();T;--T)
    {
        n=read();m=read();cnt=0;
        for(register int i=1;i<=n;++i) head[i]=0;
        for(register int i=1;i<n;++i) ins(read(),read());
        dep[1]=0;Dfs(1,0);int mx=0,From=1;
        for(register int i=1;i<=m;++i) 
            a[i]=read(),b[i]=read(),d[i]=read(),
            (dep[a[i]]+dep[b[i]]-d[i]+1)/2>mx?(mx=(dep[a[i]]+dep[b[i]]-d[i]+1)/2,From=i):0;
        for(From=a[From];dep[From]>mx;From=fa[From]);
        dep[From]=0;Dfs(From,0);bool flag=1;
        for(register int i=1;i<=m;++i) 
            if(dep[a[i]]+dep[b[i]]>d[i]) {flag=0;break;}
        if(flag) printf("TAK %d\n",From);
        else puts("NIE");
    }
    return 0;
}
posted @ 2017-06-03 21:05  FallDream  阅读(347)  评论(0编辑  收藏  举报