zoukankan      html  css  js  c++  java
  • FCS省选模拟赛 Day7

    Description

     Solution

    T1 island

    考虑把问题成两部分计算

    1. 纵坐标的距离和很好计算,在输入的同时一次计算了就完事

    2. 横坐标又分成两部分

      • 分别在(y)轴不同侧的矩形的距离和同样也比较好算,因为不会回头

      • 然后是在(y)轴同侧的矩形,我们以右侧的为例,左侧同理

        第一步,把两个点之间横坐标的移动距离分解成(r_x+r_y-2r_k)(r_k)就是最大的能“回头”的横坐标

        第二步,我们直接计算出(r_x+r_y)部分的和

        第三步

        减去(r_k)相当于在每个(leq r_k)的位置减(1)

        相当于从右往左扫,每次加上当前扫描线右边部分的相互联通的点对数

        我们可以用并查集维护当前的联通情况

        一个联通集合在两次进行合并的中间的联通性是不变的

        也就是他在中间每个位置的点对数量是个二次函数,对它求和,利用小学奥数

        [sum_{i=1}^{n} i^2 =frac{n(n+1)(2n+1)}{6} ]

        就可以求出一个公式啦

        每次在合并前,进行一次计算即可

        好难写啊......

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define int ll
    #define reg register
    const int MN=1e6+5,mod=998244353,inv2=499122177,inv6=166374059;
    int n,l[MN],r[MN];
    int n_l,n_r,l_r,N,Le,ans,dec;
    int c1(int x){return 1ll*x*x%mod;}
    int c2(int x){return 1ll*x*(x+1)%mod*(2ll*x%mod+1)%mod*inv6%mod;}
    int c3(int a1,int an,int n_){return 1ll*n_*(a1+an)%mod*inv2%mod;}
    int fa[MN],id[MN],Nm[MN],d[MN];
    bool cmp1(int x,int y){return l[x]<l[y];}
    bool cmp2(int x,int y){return r[x]<r[y];}
    int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);}
    void union_(int x,int y){fa[x]=y;d[y]+=d[x];(Nm[y]+=Nm[x])%=mod;}
    void Calc(int x,int k)
    {
    	dec=(dec+1ll*c1(Nm[x])*k%mod+1ll*c3(2,2*k,k)*d[x]%mod*Nm[x]%mod+1ll*c2(k)*c1(d[x])%mod)%mod;
    	(Nm[x]+=1ll*d[x]*k)%=mod;
    }
    void calc(int *a)
    {
    	memset(fa,0,sizeof fa);
    	memset(Nm,0,sizeof Nm);
    	memset(d,0,sizeof d);
    	id[0]=a[0]=0;
    	reg int xx;
    	for(reg int i=n;~i;--i)
    	{
    		fa[id[i]]=id[i];d[id[i]]=1;
    		if(id[i]>1&&fa[id[i]-1]) xx=getf(id[i]-1),Calc(xx,a[xx]-a[id[i]]),union_(xx,id[i]);
    		if(id[i]<n&&fa[id[i]+1]) xx=getf(id[i]+1),Calc(xx,a[xx]-a[id[i]]),union_(xx,id[i]);
    	}
    	/*
    		if(a[i]==a[i-1]) ++d;
    		else
    		{
    			++d;k=a[i]-a[i-1];
    			dec=(dec+1ll*c1(Nm)*k%mod+1ll*c3(2,2*k,k)*d%mod*Nm%mod+1ll*c2(k)*c1(d)%mod)%mod;
    			Nm+=1ll*d*k%mod;
    		}
    	*/
    }
    signed main()
    {
    	char sss[10];
    	n=read();scanf("%s",sss);
    	reg int i;
    	for(i=1;i<=n;++i)
    	{
    		l[i]=-read(),r[i]=read();
    		l_r=(l_r+1ll*(r[i]+1)*(r[i])%mod*inv2%mod)%mod;
    		n_l=(n_l+l[i])%mod;
    		n_r=(n_r+r[i])%mod;
    		ans=(ans+2ll*(l[i]+r[i])*(Le+(mod-1ll*(n-i+1)*N%mod)%mod)%mod)%mod;
    		N=(N+r[i]+l[i])%mod;
    		Le=(Le+1ll*(r[i]+l[i])*(n-i+1)%mod)%mod;
    	}
    	for(i=1;i<=n;++i) ans=(ans+(l_r*2%mod+(l[i]-1)*n_r%mod)*l[i]%mod)%mod;
    	for(i=1;i<=n;++i) ans=(ans+2ll*c3(1,l[i],l[i])*n_l%mod)%mod;
    	for(i=1;i<=n;++i) ans=(ans+2ll*c3(1,r[i],r[i])*n_r%mod)%mod;
    	for(i=1;i<=n;++i) id[i]=i;
    	std::sort(id+1,id+n+1,cmp1);
    	calc(l);
    	for(i=1;i<=n;++i) id[i]=i;
    	std::sort(id+1,id+n+1,cmp2);
    	calc(r);
    	dec=2ll*dec%mod;
    	ans=(ans+mod-dec)%mod;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    T2 river

    水题。

    每个时间都能找到最早的转移时间,然后一定成环,把环找出来直接算就行了

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define reg register
    const int MN=1e6;
    int n,m,a[MN<<1],b[MN<<1];
    struct Node{int val,id;}d;
    bool vis[MN];
    int que[MN],pos[MN],tt,len[MN];
    ll ans;
    int main()
    {
    	n=read()+1;m=read();
    	reg int i;
    	for(i=0;i<m;++i) a[i]=a[i+m]=read();
    	b[m*2-1]=a[m*2-1];d=(Node){m*2-1+b[m*2-1],m*2-1};
    	for(i=m*2-2;~i;--i)
    	{
    		b[i]=min(a[i],b[d.id]+d.id-i);
    		if(i+b[i]<d.val) d=(Node){i+b[i],i};
    	}
    	for(i=0;!vis[i];)
    	{
    		vis[i]=true;
    		que[++tt]=i;
    		len[tt]=len[tt-1]+b[i];
    		pos[i]=tt;
    		i=(i+b[i])%m;
    	}
    	int _r=tt-pos[i]+1,pre=pos[i]-1,len_r=len[tt]-len[pos[i]-1];
    	if(n>=pre) ans+=len[pre],n-=pre+1;
    	ans+=1ll*len_r*(n/_r);n=n%_r+pre;
    	ans+=len[n]-len[pre];
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    T3 cac

    建出圆方树,每次修改操作可以看成是对路径上的方点(+val)
    如果(lca)是方点,则它的fa的圆点(+val)
    否则(lca)的权值(+val)
    最后的每个点答案应该是他父亲方点的值和自己的权值之和
    树链剖分+树状数组

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define reg register 
    #define int ll
    const int MN=3e5+5,mod=998244353;
    inline ll read()
    {
    	ll x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();x%=mod;}
    	return x*f;
    }
    int N,M,K;
    struct edge{int to,nex;}e[MN<<3],E[MN<<2];
    int hr[MN],Hr[MN<<1],en,En;
    bool sq[MN<<1];
    inline void ins(int f,int t,int *h,edge *ed,int &end)
    {
    	ed[++end]=(edge){t,h[f]};h[f]=end;
    	ed[++end]=(edge){f,h[t]};h[t]=end;
    }
    int ind,dfn[MN],low[MN],st[MN],Tp,num;
    void tj(int x)
    {
    	dfn[x]=low[x]=++ind;st[Tp++]=x;reg int i;
    	for(i=hr[x];i;i=e[i].nex)
    	{
    		if(!dfn[e[i].to])
    		{
    			tj(e[i].to);low[x]=min(low[x],low[e[i].to]);
    			if(low[e[i].to]==dfn[x])
    				for(sq[++num]=true,Hr[num]=0,ins(num,x,Hr,E,En);st[Tp]!=e[i].to;--Tp)ins(num,st[Tp-1],Hr,E,En);
    		}
    		else low[x]=min(low[x],dfn[e[i].to]);
    	}
    }
    int dind,L[MN<<1],siz[MN<<1],mx[MN<<1],top[MN<<1],fa[MN<<1],dep[MN<<1];
    void dfs1(int x,int f)
    {
    	fa[x]=f;siz[x]=1;dep[x]=dep[f]+1;
    	reg int i;
    	for(i=Hr[x];i;i=E[i].nex)if(E[i].to^f)
    		dfs1(E[i].to,x),siz[x]+=siz[E[i].to],siz[E[i].to]>siz[mx[x]]?mx[x]=E[i].to:0;
    }
    void dfs2(int x,int tp)
    {
    	top[x]=tp;L[x]=++dind;
    	if(mx[x]) dfs2(mx[x],tp);reg int i;
    	for(i=Hr[x];i;i=E[i].nex)if((E[i].to^fa[x])&&(E[i].to^mx[x])) dfs2(E[i].to,E[i].to);
    }
    class _Tr
    {
    	int T[MN<<1];
    	void C(int x,int y){for(;x<=6e5;x+=(x&(-x))) T[x]+=y,T[x]%=mod;}
    	int G(int x){int r=0;for(;x;x-=(x&(-x)))r+=T[x],r%=mod;return r;}
    	public:
    		void Md(int l,int r,int y){C(l,y);C(r+1,(mod-y)%mod);}
    		int Get(int x){return G(x);}
    }T;
    int val[MN<<1];
    inline void Md(int x,int y,int ad)
    {
    	for(;top[x]^top[y];)
    	{
    		if(dep[top[x]]>dep[top[y]])
    		{
    			T.Md(L[top[x]],L[x],ad);
    			x=fa[top[x]];
    		}
    		else
    		{
    			T.Md(L[top[y]],L[y],ad);
    			y=fa[top[y]];
    		}
    	}
    	if(dep[x]>dep[y]) std::swap(x,y);
    	T.Md(L[x],L[y],ad);
    	if(sq[x]&&fa[x]) val[fa[x]]+=ad,val[fa[x]]%=mod;
    	if(!sq[x]) val[x]+=ad;
    }
    int Query(int x)
    {
    	int r=val[x];
    	if(fa[x]) r+=T.Get(L[fa[x]]);
    	r%=mod;
    	return r;
    }
    signed main()
    {
    	num=N=read();M=read();K=read();
    	reg int opt,x,y,i;
    	for(i=1;i<=M;++i) x=read(),ins(x,read(),hr,e,en);
    	tj(1);dfs1(1,0);dfs2(1,1);
    	while(K--)
    	{
    		opt=read();x=read();
    		if(opt==0) y=read(),Md(x,y,read()%mod);
    		if(opt==1) printf("%d
    ",Query(x));
    	}
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    【知了堂学习笔记】java 正则表达式
    【知了堂学习笔记】java 接口与抽象类
    【知了堂学习笔记】java web 简单的登录
    【知了堂学习笔记】java IO流归纳总结
    【知了堂学习笔记】java 自定义异常
    【知了堂学习笔记】java 方法重载与重写的归纳
    编译链接符号重定位流程简述
    项目用到了lua的哪些部分
    lua协程实现简析
    杂乱无章
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/fcs_noi2019_day7.html
Copyright © 2011-2022 走看看