HDU 6562 Lovers 题解

331 阅读2分钟

题目链接

思路

显然是线段树,考虑给长度为numnum的一段区间左边加一坨数字d1d2...dmd_1d_2...d_m,记为leftleft,则对应地右边就加了dmdm1...d1d_md_{m-1}...d_1,记为rightright,设len=10mlen=10^m,记最小的大于第ii个数字的1010的幂为rateirate_i,如234234对应的raterate10001000。那么包裹之后区间和就变成:

i=LRailen+rateilenleft+right=leni=LRai+lenlefti=LRratei+numright\sum \limits_{i=L}^R a_i\cdot len+rate_i\cdot len\cdot left+right\\ =len\sum \limits_{i=L}^Ra_i+len\cdot left\sum \limits_{i=L}^Rrate_i+num\cdot right

发现区间所有数字的raterate在操作之后都变成ratelenrate\cdot len,因此可以维护区间raterate和,实现打标记。

另外再维护一下区间左边右边分别加了那些数字即可。

代码

#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
const ll N=1E5+10,P=1E9+7;
ll n,q;
ll sum[4*N],rate[4*N],L[4*N],R[4*N],taglen[4*N];
void update(ll p)
{
	sum[p]=(sum[lc]+sum[rc])%P;
	rate[p]=(rate[lc]+rate[rc])%P;
}
void build(ll p,ll l,ll r)
{
	taglen[p]=1;
	if(l==r)
	{
		rate[p]=1;
		return;
	}
	ll mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	update(p);
}
void flag(ll p,ll l,ll r,ll left,ll right,ll len)
{
	ll num=r-l+1;
	sum[p]=((sum[p]*len%P+right*num%P)%P+rate[p]*len%P*left%P)%P;
	L[p]=(L[p]+taglen[p]*left%P)%P;
	R[p]=(R[p]*len%P+right)%P;
	rate[p]=rate[p]*len%P*len%P;
	taglen[p]=taglen[p]*len%P;
}
void flag_(ll p,ll l,ll r,ll left,ll right,ll len)
{
	ll num=r-l+1;
	sum[p]=((sum[p]*len%P+right*num%P)+rate[p]*left%P)%P;
	L[p]=(L[p]*len+left*taglen[p]%P*taglen[p]%P)%P;
	R[p]=(R[p]*len+right)%P;
	rate[p]=rate[p]*len%P*len%P;
	taglen[p]=taglen[p]*len%P;
}
void push_down(ll p,ll l,ll r)
{
	ll mid=(l+r)>>1;
	flag(lc,l,mid,L[p],R[p],taglen[p]);
	flag(rc,mid+1,r,L[p],R[p],taglen[p]);
	L[p]=R[p]=0;
	taglen[p]=1;
}
void modify(ll p,ll l,ll r,ll al,ll ar,ll val)
{
	if(al<=l && ar>=r)
	{
		flag(p,l,r,val,val,10);
		return;
	}
	if(taglen[p]!=1)
		push_down(p,l,r);
	ll mid=(l+r)>>1;
	if(al<=mid)
		modify(lc,l,mid,al,ar,val);
	if(ar>mid)
		modify(rc,mid+1,r,al,ar,val);
	update(p);
}
ll query(ll p,ll l,ll r,ll al,ll ar)
{
	if(al<=l && ar>=r)
		return sum[p];
	ll mid=(l+r)>>1,ret=0;
	if(taglen[p]!=1)
		push_down(p,l,r);
	if(al<=mid)
		ret=(ret+query(lc,l,mid,al,ar))%P;
	if(ar>mid)
		ret=(ret+query(rc,mid+1,r,al,ar))%P;
	return ret;
}
void print()
{
	rep(i,1,n)
		op(query(1,1,n,i,i));
	en;
}
void solve()
{
	read(n,q);
	rep(p,1,4*n)
		sum[p]=rate[p]=L[p]=R[p]=taglen[p]=0;
	build(1,1,n);
	char ty[100];
	ll l,r,d;
	while(q--)
	{
		scanf("%s",ty);
		if(ty[0]=='w')
		{
			read(l,r,d);
			modify(1,1,n,l,r,d);
		}
		else
		{
			read(l,r);
			OP(query(1,1,n,l,r));
		}
	}
}
int main()
{
	int _;
	cin>>_;
	ll cnt=0;
	while(_--)
	{
		printf("Case %lld:\n",++cnt);
		solve();
	}
}