zoukankan      html  css  js  c++  java
  • 7367. 【2021.11.10NOIP提高组联考】可笑的 wenhao801

    Description

    (n) 列无助的袋鼠并排摆放在平面直角坐标系内,每个无助的袋鼠可以近似看成一个 (1 imes 1) 的正方形, 第 (i) 列无助的袋鼠在 (x=i-1)(x=i) 之间,从 (x) 轴开始向上摆放,其中第 (i) 列无助的袋鼠高度为 (a_{i}) (即这一列有 (a_{i}) 个无助的袋鼠),保证所有 (a_{i}) 互不相同

    空中有 (m) 个可笑的 wenhao801,每个可笑的 wenhao801 也可以看成一个 (1 imes 1) 的正方形,第 (i) 个可 笑的 wenhao801 坐标为 (left(x_{i}, y_{i} ight)) ,表示这个可笑的 wenhao801 在第 (x_{i}) 列无助的袋鼠上方,且高度为 (y_{i}) (高度定义为上底的 (y) 坐标),保证可笑的 wenhao801 不与无助的袋鼠重合,但两个可笑的 wenhao801 可能重合

    定义一个无序可笑的 wenhao801 对 ((p, q)(p eq q)) 是「黑暗的」当且仅当从其中高度更高的可笑的 wenhao801 存在一条不升的路径到达高度更低的可笑的 wenhao801,并且不经过任何无助的袋鼠。

    每个可笑的 wenhao801 有一个体重 (w_{i}) ,定义一个可笑的 wenhao801 对 ((p, q)) 的权值为他们体重差的 平方,即 (left(w_{p}-w_{q} ight)^{2})

    求所有「黑暗的」可笑的 wenhao801 对的权值和,答案对 (998244353)​ 取模。

    (1le n,mle 5 imes 10^5)

    Solution

    先求出每个点最左能到哪一列,最右能到哪一列,这个可以通过二分+ST 表来实现。

    对于一个点 ((x_i,y_i)),我们可以求出他左边的有贡献的点和右边的有贡献的点,计算答案可以用线段树。

    考虑好做一点,先将点按照高度为第一关键字排序,每次对于一个点,先求他的答案在将他插入线段树中,这样可以保证产生权值的点都是符合高度限制的。

    线段树记录 3 个值,个数,一次方和,二次方和。至于为什么,将 ((w_i-w_j)^2) 展开就知道了。

    Code

    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #define N 500005
    #define mod 998244353
    #define ll long long
    using namespace std;
    struct node
    {
    	ll x,y,v;
    }p[N];
    struct seg
    {
    	ll num,sig,mi;
    }tree[N<<2];
    ll n,m,l,r,mid,res,ans,h[N],lt[N],rt[N],f[N<<1][20];
    bool cmp(node x,node y)
    {
    	if (x.y<y.y) return true;
    	if (x.y>y.y) return false;
    	return x.x<=y.x;
    }
    ll get(ll x,ll y)
    {
    	ll lg=log2(y-x+1);
    	return max(f[x][lg],f[y-(1<<lg)+1][lg]);
    }
    void modify(ll now,ll l,ll r,ll p,ll v)
    {
    	if (l==r)
    	{
    		tree[now].num++;
    		tree[now].mi=(tree[now].mi+v*v)%mod;
    		tree[now].sig=(tree[now].sig+v)%mod;
    		return;
    	}
    	ll mid=(l+r)>>1;
    	if (p<=mid) modify(now<<1,l,mid,p,v);
    	else modify(now<<1|1,mid+1,r,p,v);
    	tree[now].num=tree[now<<1].num+tree[now<<1|1].num;
    	tree[now].mi=(tree[now<<1].mi+tree[now<<1|1].mi)%mod;
    	tree[now].sig=(tree[now<<1].sig+tree[now<<1|1].sig)%mod;
    }
    ll query(ll now,ll l,ll r,ll p,ll q,ll ty)
    {
    	if (p>q) return 0;
    	if (l>=p&&r<=q)
    	{
    		if (ty==1) return tree[now].num;
    		if (ty==2) return tree[now].sig;
    		if (ty==3) return tree[now].mi;
    	}
    	ll mid=(l+r)>>1;
    	if (q<=mid) return query(now<<1,l,mid,p,q,ty);
    	else if (p>mid) return query(now<<1|1,mid+1,r,p,q,ty);
    	else return (query(now<<1,l,mid,p,q,ty)+query(now<<1|1,mid+1,r,p,q,ty))%mod;
    }
    int main()
    {
    	freopen("flame.in","r",stdin);
    	freopen("flame.out","w",stdout);
    	scanf("%lld%lld",&n,&m);
    	for (ll i=1;i<=n;++i)
    		scanf("%lld",&h[i]),f[i][0]=h[i];
    	h[0]=h[n+1]=mod;
    	for (ll j=1;j<=19;++j)
    		for (ll i=1;i<=n;++i)
    			f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    	for (ll i=1;i<=m;++i)
    		scanf("%lld%lld%lld",&p[i].x,&p[i].y,&p[i].v);
    	sort(p+1,p+m+1,cmp);
    	for (ll i=1;i<=m;++i)
    	{
    		l=0;r=p[i].x-1;res=0;
    		while (l<=r)
    		{
    			mid=(l+r)>>1;
    			if (get(mid,p[i].x-1)>=p[i].y) res=mid,l=mid+1;
    			else r=mid-1;
    		}
    		lt[i]=res;
    		l=p[i].x+1;r=n+1;res=n+1;
    		while (l<=r)
    		{
    			mid=(l+r)>>1;
    			if (get(p[i].x+1,mid)>=p[i].y) res=mid,r=mid-1;
    			else l=mid+1;
    		}
    		rt[i]=res;
    		lt[i]++;rt[i]--;
    	}
    	for (ll i=1;i<=m;++i)
    	{
    		ll num=query(1,1,n,lt[i],p[i].x,1),sig=query(1,1,n,lt[i],p[i].x,2),mi=query(1,1,n,lt[i],p[i].x,3);
    		ans=(ans+num*p[i].v%mod*p[i].v%mod)%mod;
    		ans=(ans-(2*sig*p[i].v%mod)+mod)%mod;
    		ans=(ans+mi)%mod;
    		num=query(1,1,n,p[i].x+1,rt[i],1),sig=query(1,1,n,p[i].x+1,rt[i],2),mi=query(1,1,n,p[i].x+1,rt[i],3);
    		ans=(ans+num*p[i].v%mod*p[i].v%mod)%mod;
    		ans=(ans-(2*sig*p[i].v%mod)+mod)%mod;
    		ans=(ans+mi)%mod;
    		modify(1,1,n,p[i].x,p[i].v);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    jsonp 原理和基本使用
    jsonplaceholder直接提供模拟测试数据
    为什么要学mock
    vue基础知识和案例
    winform datagridview中combobox列改变选项时触发其他列变化
    将DataGridView转换为DataTable
    C#中删除字符串最后一个字符串的几种方式
    C#中成员变量和局部变量的区别
    WinForm窗体中如何在一个窗体中取到另一个窗体的值
    ComboBox 中 DisplayMember 和 ValueMember有何区别
  • 原文地址:https://www.cnblogs.com/Livingston/p/15535770.html
Copyright © 2011-2022 走看看