首页 > 其他分享 >Codeforces Round 947 (Div. 1 + Div. 2) E. Chain Queries

Codeforces Round 947 (Div. 1 + Div. 2) E. Chain Queries

时间:2024-05-26 20:11:28浏览次数:14  
标签:CI Chain int 947 son dep 端点 Div now

本来决定开摆养生不打的,但11点半的时候点进去看到这个题是个疑似DS,写题的欲望瞬间高涨,然后就40min写了这个题

然而赛中并不能提交,只好等到第二天早上再交一发,没想到还WA了一发才过

首先这题如果我们能确定当前黑色点集的链的两个端点\(x,y\)的话,这个题就非常显然了

只需要求出\((x,y)\)路径上黑色点的数量,当这个值与\((x,y)\)路径的长度、以及黑色节点的总个数都相等时才合法

那么现在问题是如何确定这两个端点,一个很自然的观察是一定有一个端点是DFS序最大的点,因为根据DFS序的性质,在该点的子树内一定没有其它的黑色点

那另一个端点该取什么好呢,单纯的考虑DFS序最小、深度最小、深度次大这些限制都会有反例,因此需要往别的方向思考

考虑诸如树上莫队处理树上路径时,我们用到的是欧拉序,因此我们对于每个点额外维护它在欧拉序中最后一次出现的前后关系

那么根据欧拉序的性质,欧拉序最小的点的子树内也一定没有其它的黑色点,因此可以用来作为第二个端点

但这种情况有一个Corner Case,即样例中\(1,3,4\)为黑点的情况,两次得到的端点会是重合的

不过好在我们仔细分析一波后,会发现当且仅当这条链的两个端点有祖先关系时会发生这种情况,此时我们把另一个端点换成欧拉序最大的点(就是这条链最上方的节点)即可

用两个set维护点集,同时用树剖+线段树维护黑点个数,总复杂度\(O(n\log^2n)\)

#include<cstdio>
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<utility>
#define RI register int
#define CI const int&
using namespace std;
typedef pair <int,int> pi;
const int N=200005;
int t,n,q,c[N],x,y; vector <int> v[N];
class Segment_Tree
{
	private:
		int sum[N<<2];
	public:
		#define TN CI now=1,CI l=1,CI r=n
		#define LS now<<1,l,mid
		#define RS now<<1|1,mid+1,r
		inline void build(TN)
		{
			sum[now]=0; if (l==r) return;
			int mid=l+r>>1; build(LS); build(RS);
		}
		inline void updata(CI pos,CI mv,TN)
		{
			sum[now]+=mv; if (l==r) return; int mid=l+r>>1;
			if (pos<=mid) updata(pos,mv,LS); else updata(pos,mv,RS);
		}
		inline int query(CI beg,CI end,TN)
		{
			if (beg<=l&&r<=end) return sum[now]; int mid=l+r>>1,ret=0;
			if (beg<=mid) ret+=query(beg,end,LS);
			if (end>mid) ret+=query(beg,end,RS);
			return ret;
		}
		#undef TN
		#undef LS
		#undef RS
}SEG;
namespace Heavy_Division
{
    int idx,idxr,top[N],dep[N],sz[N],dfn[N],dfnr[N],anc[N],son[N];
    inline void DFS1(CI now=1,CI fa=0)
    {
        son[now]=0; sz[now]=1; dep[now]=dep[fa]+1; anc[now]=fa;
        for (int to:v[now]) if (to!=fa)
        {
            DFS1(to,now); sz[now]+=sz[to];
            if (sz[to]>sz[son[now]]) son[now]=to;
        }
    }
    inline void DFS2(CI now=1,CI tf=1)
    {
        dfn[now]=++idx; top[now]=tf;
        if (son[now]) DFS2(son[now],tf);
        for (int to:v[now]) if (to!=anc[now]&&to!=son[now]) DFS2(to,to);
        dfnr[now]=++idxr;
    }
    inline int querysum(int x,int y)
    {
    	int ret=0;
    	while (top[x]!=top[y])
    	{
    		if (dep[top[x]]<dep[top[y]]) swap(x,y);
    		ret+=SEG.query(dfn[top[x]],dfn[x]);
    		x=anc[top[x]];
    	}
    	if (dep[x]<dep[y]) swap(x,y);
		ret+=SEG.query(dfn[y],dfn[x]);
		return ret;
    }
    inline int LCA(int x,int y)
    {
    	while (top[x]!=top[y])
    	{
    		if (dep[top[x]]<dep[top[y]]) swap(x,y);
    		x=anc[top[x]];
    	}
    	if (dep[x]<dep[y]) swap(x,y);
		return y;
    }
};
using namespace Heavy_Division;
int main()
{
	//freopen("E.in","r",stdin); freopen("E.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d%d",&n,&q),i=1;i<=n;++i) scanf("%d",&c[i]);
		for (i=1;i<n;++i) scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
		set <pi> FT,BK; DFS1(); DFS2(); SEG.build();
		for (i=1;i<=n;++i) if (c[i]) SEG.updata(dfn[i],c[i]),FT.insert(pi(dfn[i],i)),BK.insert(pi(dfnr[i],i));
		for (i=1;i<=q;++i)
		{
			scanf("%d",&x);
			if (c[x]) FT.erase(pi(dfn[x],x)),BK.erase(pi(dfnr[x],x));
			else FT.insert(pi(dfn[x],x)),BK.insert(pi(dfnr[x],x));
			SEG.updata(dfn[x],(c[x]^1)-c[x]); c[x]^=1;
			if (FT.empty()) { puts("No"); continue; }
			int x=FT.rbegin()->second,y=BK.begin()->second;
			if (x==y) y=BK.rbegin()->second;
			int tmp=dep[x]+dep[y]-2*dep[LCA(x,y)]+1;
			puts(tmp==querysum(x,y)&&querysum(x,y)&&tmp==FT.size()?"Yes":"No");
		}
		for (idx=idxr=0,i=1;i<=n;++i) v[i].clear();
	}
	return 0;
}

PS:后面看题解和祁神代码好像这题有个更简单的分类讨论做法

大体就是根据两种链的形态,根据每个黑色点相邻的黑色点数量来判断,但我感觉那种方法写起来还是细节挺多的,没有这种大力的方法想起来简单

标签:CI,Chain,int,947,son,dep,端点,Div,now
From: https://www.cnblogs.com/cjjsb/p/18214222

相关文章

  • 24.2.13 ~ 4.13 Codeforces Round 925 & 926 & 934 & 939 (Div.3 / Div.2 * 3)
    925Div.3Solve:A~G(7/7)Rank:95Rating:\(0+706=706\)(\(1400+206=1606\))发挥评价:Normal+本场没什么有价值题目。926Div.2Solve:A~DF(5/6)Rank:72Rating:\(706+575=1281\)(\(1606+225=1831\))发挥评价:Good本场没有什么失误。CF1929E*2300(me*2300)选......
  • Codeforces Round 947 (Div. 1 + Div. 2)
    Solve:A~ERank:425Rating:\(1744+195=1939\)(\(1894+95=1989\))发挥评价:Normal本场问题:E先WAon4,较快找出问题后修改WAon27,就又急了(重现上午),开始怀疑做法正确性未果,结果1h后才发现是代码出现问题。注意先检查代码漏洞而不是先怀疑正确性(尤其是错在后面时候,要是正......
  • 大模型开发:第一批用 LangChain 的程序员,早就已经碾压同事了。。
    今年招聘市场确实是好点了,我发现群友都在讨论,得赶快学点AI大模型。他们有的是想正式转到一些新兴的AI行业,需要系统的学习训练。更多的是想跟已有的技能结合,辅助编程提效,或上手实操应用,增加自己的职场竞争力。这也可以理解,ChatGPT推出仅一年半的时间,就将生成式AI推......
  • 【智应数】Markow chains
    MarkowChain&StationaryDistributionDef(FiniteMarkowChain).Let\(\Omega\)beafinitesetofstates,\(\forallx,y\in\Omega,P(x,y)\ge0\)beatransitionfunction,i.e.,\(\sum\limits_{y\in\Omega}P(x,y)=1.\)AfiniteMarkowchain......
  • CodeTON Round 3 (Div. 1 + Div. 2, Rated, Prizes!)
    切5道。A\([a_1=1]\)B\(\max(\max(xy),\max(x^2),\max(y^2))\)第一部分可以选整个数组,第二部分和第三部分是最大连续0段和1段。C操作等价于\(a_{l\simr}\oplus1\),\(b_{l\simr}\oplus1\),\(b_{1\simn}\oplus1\)。考虑先把\(a\)全部变成\(0\),使用ii......
  • CF Round946 (Div. 3)C:map的map<pair<int,int>int>映射 + 性质
    BeautifulTriplePairs题目描述Polycarpwasgivenanarray$a$of$n$integers.Hereallylikestriplesofnumbers,soforeach$j$($1\lej\len-2$)hewrotedownatripleofelements$[a_j,a_{j+1},a_{j+2}]$.Polycarpconsidersapa......
  • 使用本地大语言模型和Langchain手搓免费的AI搜索问答助手
    1概述大语言模型虽然已经有了很多的背景知识,但针对模型训练之后新产生的内容,或者领域内的知识进行提问,大模型本身通常无法准确给出回应,一个常用的解决方法是,借助检索增强生成(RAG),将能够用于回答问题的相关上下文给到大模型,利用大模型强大的理解和生成能力,来缓解这个问题。本文主......
  • Codeforces Round 946 (Div. 3) G Money Buys Less Happiness Now(反悔贪心)
    MoneyBuysLessHappinessNow1.题目大意:有n天,每天可以赚x块钱,然后每天可以通过花\(C_{i}\)块钱购买1点快乐值,然后每天赚的钱至少要在下一天才能用,问最多能获得多少快乐值。2.解题思路:我们发现天数变得很多,不能像e题那样dp了,所以要用贪心。具体来讲,我们碰到当前能买的就直接......
  • Codeforces Round 946 (Div. 3)
    C.BeautifulTriplePairs题意:优美组的定义是一共三对有且只有一对对应的数字不相同,求有多少个优美三元组思路:对于只有三对,而且只有一对不同,首先看前面遍历过的三元组会对后面的三元组产生影响,若是不记录前面对后面三元组的次数,那么我们要进行两次循环O(n^2)会寄的,因此我们......
  • LeetCode Greatest Common Divisor of Strings All In One
    LeetCodeGreatestCommonDivisorofStringsAllInOneLeetCode1071errorsfunctiongcdOfStrings(str1:string,str2:string):string{letresult=``;lettemp=[];if(str1.length>str2.length){letreg=newRegExp(str2,'g'......