zoukankan      html  css  js  c++  java
  • 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 imes) 赢的概率。
    正解先把询问离线下来,按照操作的时间顺序(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
    ,(%d,%d)
    ",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
    ",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
    ",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]
    ",dfn[u],dfn[v]-1,dfn[v],dfn[v]+siz[v]-1);
    		}
    		else printf("%lld
    ",query(1,1,n,dfn[u]));
    	}
    	return 0;
    }
    /*
    3 5
    2 1
    1 2 1
    2 1
    1 2 3
    2 1
    */
    
  • 相关阅读:
    R语言 which() 、 which.min() 、 which.max() 函数
    R rep() 函数
    R语言 一个向量的值分派给另一个向量
    R语言 sample抽样函数
    超参数 hyperparameters
    随机游走模型(Random Walk)
    随机数
    Lambda 函数与表达式
    static
    变量的申明定义
  • 原文地址:https://www.cnblogs.com/conprour/p/15336056.html
Copyright © 2011-2022 走看看