9.25模拟赛总结

前言

真不错,保留字挂分真不戳。
T1 做过。
本来 T2 暴力有 \(60\)pts ,结果用了 c++14 的保留字move直接 RE 了...
T3 暴力被卡 TLE 了...正解的分类讨论想出来了但是没想到用树状数组和 set 维护,而且没时间了。
总分 \(100\)pts.

题解

着重说一下这个 T2.
发现这种树形结构的题,转化成线段树区间维护我经常想不到...
首先普遍思路是要对于每一个动物,去打别人赢的概率是 \(\frac{1}{3}\) ,被别人打赢的概率是 \(\frac{2}{3}\) .
暴力的思路就是暴力地合并(链表,set ,并查集等均可),每次查询即为 \(3^n \times\) 赢的概率。
正解先把询问离线下来,按照操作的时间顺序\(v->u\) 建边(其实只需要链前倒序建边即可)并且 dfs 求出 dfs 序。
然后就可以把每段要操作的笼子转化成连续的区间。区间连续就能用线段树维护区间乘了。
线段树的叶子节点初始化为 \(3^n\) ,维护的时候只需要维护叶子节点即可,因为单点查只有叶节点有意义。
区间乘不太常见,注意一下lazy数组的更新和清空。
(线段树区间修改别忘记套dfn)

T2-zoo 代码

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f,N = 2e5+10,mod = 998244353;
#define ll long long
#define ls k<<1
#define rs k<<1|1
#define mid ((l+r)>>1)
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n,m;
inline ll qpow(ll x,ll y)
{
	ll ret=1;
	while(y)
	{
		if(y&1) ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
const int inv = qpow(3,mod-2);
int dfn[N],tim,oud[N],siz[N],mi3;
ll tree[N<<2],lazy[N<<2];
void build(int k,int l,int r)
{
	lazy[k]=1;
	if(l==r) {tree[k]=mi3;return;}
	build(ls,l,mid);
	build(rs,mid+1,r);
	//tree[k]=tree[ls]*tree[rs]%mod;
}
inline void Add(int k,int l,int r,int v)
{
	tree[k]=tree[k]*v%mod;
	lazy[k]=lazy[k]*v%mod;
	//printf("lazy[k]=%lld\n,(%d,%d)\n",lazy[k],l,r);
}
inline void pushdown(int k,int l,int r)
{
	if(lazy[k]==1) return;
	Add(ls,l,mid,lazy[k]);
	Add(rs,mid+1,r,lazy[k]);
	lazy[k]=1;//懒标记不清空,亲人两行泪 
}
void modify(int k,int l,int r,int x,int y,int v)
{
	if(x<=l&&r<=y) {Add(k,l,r,v);return;}
	pushdown(k,l,r);
	if(x<=mid) modify(ls,l,mid,x,y,v);
	if(y>mid) modify(rs,mid+1,r,x,y,v);
//	tree[k]=tree[ls]*tree[rs]%mod; 
}
ll query(int k,int l,int r,int x)
{
//	printf("tree[%d]=%d\n",k,tree[k]);
	if(l==r) return tree[k];
	pushdown(k,l,r);
	
	if(x<=mid) return query(ls,l,mid,x);
	else return query(rs,mid+1,r,x);
}
int head[N],ecnt=-1;
struct edge
{
	int nxt,to;
}a[N<<1];
struct ask
{
	int op,u,v;
}q[N];
inline void add(int x,int y)
{
	a[++ecnt]=(edge){head[x],y};
	head[x]=ecnt;
}
void dfs(int u,int fa)
{
	dfn[u]=++tim;siz[u]=1;
	for(int i=head[u];~i;i=a[i].nxt)
	{
		int v=a[i].to;
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
	}
}

int main()
{
	memset(head,-1,sizeof(head));
	n=read(),m=read();
	mi3=qpow(3,n);
	build(1,1,n);	
	for(int i=1;i<=m;i++)
	{
		q[i].op=read(),q[i].u=read();
		if(q[i].op==1) q[i].v=read(),oud[q[i].v]++; 
	}
	for(int i=m;i>=1;i--)//倒序建边日神仙 
	{
		int op=q[i].op,u=q[i].u,v=q[i].v;
		if(op==1) add(v,u),add(u,v);
	}
	for(int i=1;i<=n;i++) 
		if(!oud[i]) dfs(i,0);
//	for(int i=1;i<=n;i++) 
//		printf("dfn[%d]=%d,siz[%d]=%d\n",i,dfn[i],i,siz[i]);
	for(int i=1;i<=m;i++)
	{
		int op=q[i].op,u=q[i].u,v=q[i].v;
		if(op==1)
		{
			modify(1,1,n,dfn[u],dfn[v]-1,2*inv);
			modify(1,1,n,dfn[v],dfn[v]+siz[v]-1,inv);
//			printf("[%d,%d]  [%d,%d]\n",dfn[u],dfn[v]-1,dfn[v],dfn[v]+siz[v]-1);
		}
		else printf("%lld\n",query(1,1,n,dfn[u]));
	}
	return 0;
}
/*
3 5
2 1
1 2 1
2 1
1 2 3
2 1
*/
posted @ 2021-09-25 23:26  conprour  阅读(37)  评论(0编辑  收藏  举报