JZOJ2963Tree

题目大意及模型转换

给定由N个结点组成的树。每次询问如果断掉第z条边并在x与y间连边n个结点是否连通。n<=200000,询问个数m<=2000000。
这道题比较水。。。
是输出NO,否输出YES(这是题目背景的问题)。

考虑简化

断了一条边后,很显然分成了两个连通块。添加一条新的边使得这两个连通块可以缩为一个连通块,那么这条边连接的两个结点必须分别在两个连通块中。现在问题变为了判断两个结点是否在同一个连通块中。我们首先可以把无根树定一个根,蒟蒻我通常用1。转化为有根树后。每次断开的边如果是连接j与k,那么其中一个连通块是以这两个点其中一个为根的子树。而另一个,是整个树排除那个子树,不规则,很难判是否在其中。但是仔细一想,只有两个连通块,不在其中一个就肯定在另一个。因此只要判其中一个在子树内那么另一个是否不在子树内即可。

时间戳

说到判断一个点在不在某子树内,其实相当于判断这个点是否有一个祖先为该子树的根节点。这个问题可以用时间戳解决。
f[i] 为第一次进入结点i的时间。
g[i] 为离开结点i的时间。
我们规定每走一步时间+1(即顺着一条边从一个结点走到另一个结点)。
很显然,如果j是k的祖先(j=k也视为j是k的祖先)必须满足:
f[j]<=f[k]
g[j]>=g[k]
如果不允许j=k也视为j是k的祖先则去掉等于号。
那么就完美解决了。

注意

如何得知第z条边连着的j与k哪个造成的连通块是一棵子树?
看看谁的f值大。

参考程序

一次AC(汪汪汪)

#include<cstdio>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int b[200005][3];
int f[200005],g[200005],h[200005],go[400010],next[400010];
int i,j,k,l,t,n,m,tot,top,x,y,z;
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;
}
void add(int x,int y){
    go[++tot]=y;
    next[tot]=h[x];
    h[x]=tot;
}
void dfs(int x,int y){
    f[x]=++top;
    int t=h[x];
    while (t){
        if (go[t]!=y) dfs(go[t],x);
        t=next[t];
    }
    g[x]=++top;
}
bool pd(int x,int y){
    return (f[x]>=f[y])&&(g[x]<=g[y]);
}
int main(){
    n=read();
    fo(i,1,n-1){
        j=read();k=read();
        b[i][1]=j;b[i][2]=k;
        add(j,k);
        add(k,j);
    }
    dfs(1,0);
    m=read();
    fo(i,1,m){
        x=read();y=read();z=read();
        j=b[z][1];k=b[z][2];
        if (f[j]<f[k]) l=k;else l=j;
        if (pd(x,l)!=pd(y,l)) printf("NO\n");else printf("YES\n");
    }
}
JZOJ 5186. 【NOIP2017提高组模拟6.30】tty's home 原创 于 2017-06-30 20:39:51 发布 · 411 阅读 · 1 · 1 · CC 4.0 BY-SA版权 文章标签: #动态规划 #树形DP 动态规划 同时被 2 个专栏收录 58 篇文章 订阅专栏 树形DP 12 篇文章 订阅专栏 本文介绍了一种利用树形动态规划(DP)解决特定匹配数问题的方法。通过定义节点匹配数并建立转移方程,文章详细阐述了如何计算不受限及受限条件下的匹配总数,并给出了解决方案的具体步骤。 Description Input Output Sample Input input 1: 5 1 1 1 1 1 1 2 2 3 3 4 4 5 input 2: 5 0 1 0 1 0 1 2 2 3 3 4 4 5 Sample Output output 1: 15 output 2: 12 Data Constraint Solution 正难则反,这题我们可以转换一下思路。姑且称 可能 符合条件的一种方案为 一个匹配 。 设 A= 不加限制的匹配数(总量), B= 不符合条件的匹配数(部分),则答案即为 A-B 。 那么我们如何求出 A 和 B 呢?可以用到 树形DP 的方法。 设 FiFi 表示以 ii 为根的子树所产生的匹配数。则有转移方程式: Fi=Fi∗Fj+Fj(j∈Soni) Fi=Fi∗Fj+Fj(j∈Soni) (逐一组合) 处理完上述式子后,再有:Fi=Fi+1 Fi=Fi+1 (单独自己也是一种匹配) 最后可以求出 A : A=∑i=1nFi A=∑i=1nFi 求 B 也同理,不过当 jj 为最值点时不转移 ii 、当 ii 为最值点时 FiFi 不 +1 。 最后 A、B 相减即可得出答案,总时间复杂度是 O(N)O(N) 。 Code #include<cstdio> #include<cstring> using namespace std; const int N=100001,mo=998244353; int tot,mx=-2147483647; int first[N],next[N<<1],en[N<<1]; int a[N]; long long f[N],g[N]; long long ans; inline int read() { int X=0,w=1; char ch=0; while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar(); return X*w; } inline void insert(int x,int y) { next[++tot]=first[x]; first[x]=tot; en[tot]=y; } inline void dfs1(int x,int y) { for(int i=first[x];i;i=next[i]) if(en[i]!=y) { dfs1(en[i],x); (f[x]+=f[x]*f[en[i]]%mo+f[en[i]])%=mo; } ans+=++f[x]; } inline void dfs2(int x,int y) { for(int i=first[x];i;i=next[i]) if(en[i]!=y) { dfs2(en[i],x); if(a[en[i]]<mx) (g[x]+=g[x]*g[en[i]]%mo+g[en[i]])%=mo; } if(a[x]<mx) (ans+=mo-++g[x])%=mo; } int main() { int n=read(); for(int i=1;i<=n;i++) if((a[i]=read())>mx) mx=a[i]; for(int i=1;i<n;i++) { int x=read(),y=read(); insert(x,y); insert(y,x); } dfs1(1,0),dfs2(1,0); printf("%lld",ans); return 0; } 一键获取完整项目代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 Felix-Lee 关注 1 1 0 分享 专栏目录 1.rar(noip2017测试数据) 07-06 【描述】"noip测试数据 noip2017提高组复赛"表明这些数据是为NOIP 2017年提高组复赛准备的。提高组是NOIP竞赛中的一个级别,针对有一定编程基础和经验的学生,比赛难度相对于入门组更高。复赛通常在初赛之后进行,... NOIP2017提高组C++试题(初赛) 10-20 NOIP2017提高组C++试题(初赛)是一套针对高级别选手的竞赛题目,包含了多项计算机科学的基础知识点,这些知识点覆盖了算法、数据结构、逻辑推理、概率计算等。 1. NOIP竞赛不再支持Pascal语言的时间点,这是一个... 【ZJOJ5186】【NOIP2017提高组模拟6.30】tty's home chen1352 509 如果直接求方案数很麻烦。 但是,我们可以反过来做:先求出所有的方案数,在减去不包含的方案数。 由于所有的路径连在一起, 于是设f[i]表示以i为根的子树中,连接到i的方案数设f[i]表示以i为根的子树中,连接到i的方案数 则f[i]=f[son]+(f[i]+1)f[i]=f[son]+(f[i]+1)表示从子树son分别到i和i其他儿子的子树的路径方案数。 由于每棵子树互不影响, 【NOIP2017提高组模拟6.30 ———————————————— 版权声明:本文为优快云博主「Felix-Lee」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.youkuaiyun.com/liyizhixl/article/details/74012007
最新发布
10-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值