• 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!

  • 相关阅读:
    Leetcode 1489找到最小生成树李关键边和伪关键边
    Leetcode 113 路径总和 II
    hdu 1223 还是畅通工程
    hdu 1087 Super Jumping! Jumping! Jumping!
    hdu 1008 Elevator
    hdu 1037 Keep on Truckin'
    湖工oj 1241 畅通工程
    湖工oj 1162 大武汉局域网
    hdu 2057 A + B Again
    poj 2236 Wireless Network
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/fcs_noi2019_day7.html
Copyright © 2020-2023  润新知