HDU 6562 lovers 2018CCPC吉林H(线段树)
题意:
初始n个空串,m个操作:
1.给[l,r]的所有字符串头尾加一个‘d’,将原字符串x变为dxd
2.求[l,r]所有字符串代表的数字之和mod 1e9+7
思路:
据说是硬核线段树。。
对于线段树我们要先找出来对于一个区间改变的时候对要询问的区间(sum)造成的变化
对于一个数x,如果对他操作了一次(头尾加一个c),那么它将变成$10x+c+c*10^{n_i+1}$,其中$n_i$表示x的实际长度(位数)
那么对当前区间操作时,当前区间的sum会变成$10sum+(r-l+1)*c+c*sumlen$,其中$sumlen=\sum_{i=l}^{r}10^{n_i+1}$
这个东西是应该写在要打懒惰标记的地方的
上式显然是有先后操作顺序的,我们只需要将操作系列$d_3d_2d_1xd_1d_2d_3$分成$d_3d_2d_1$和$d_1d_2d_3$(用两个数保存),用两个懒惰标记addl和addr分别保存
不过在pushdown的时候要注意,懒惰标记存在于已经操作过的最后一个节点里,所以要注意次序与操作的对象
在pushdown中,如果只是下传到一个节点(比如是lc),
那么$sum[lc]=addr[root]+sum[lc]*addlen[root]+addl[root]*addlen[root]*10^{n_i+1}/10$
所以对整个lc区间,$sum[lc]=\sum addr[root]+sum[lc]*addlen[root]+addl[root]+addl[root]*addlen[root]*sumlen[root]/10$
其他的都是常规操作了,注意乘的时候别溢出了
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 2e6+100; const int maxm = 2e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); ll fp(ll a, ll n){ ll ans = 1; while(n){ if(n & 1) ans *= a; a *= a; a %= mod; n >>= 1; ans %= mod; } return ans; } ll div10; ll sum[maxn]; ll sumlen[maxn]; ll addl[maxn],addr[maxn],addlen[maxn]; int t; int n, m; void build(int l, int r, int root){ int mid = (l+r)>>1; addl[root]=addr[root]=0; addlen[root]=1; if(l==r){ sum[root] = 0; sumlen[root] = 10; return; } build(lson); build(rson); sum[root]=0; sumlen[root]=sumlen[lc]+sumlen[rc]; sumlen[root]%=mod; return; } void pushdown(int l, int r, int root){ int mid = (l+r)>>1; if(addlen[root]>1){ addl[lc]=(addl[root]*addlen[lc]%mod+addl[lc])%mod; addl[rc]=(addl[root]*addlen[rc]%mod+addl[rc])%mod; addr[lc]=(addr[lc]*addlen[root]%mod+addr[root])%mod; addr[rc]=(addr[rc]*addlen[root]%mod+addr[root])%mod; addlen[lc]=addlen[lc]*addlen[root]%mod; addlen[rc]=addlen[rc]*addlen[root]%mod; sum[lc]=(addr[root]*(mid-l+1)%mod+sum[lc]*addlen[root]%mod+addl[root]*addlen[root]%mod*sumlen[lc]%mod*div10%mod)%mod; sum[rc]=(addr[root]*(r-mid)%mod+sum[rc]*addlen[root]%mod+addl[root]*addlen[root]%mod*sumlen[rc]%mod*div10%mod)%mod; sumlen[lc]=(sumlen[lc]*addlen[root]%mod*addlen[root]%mod)%mod; sumlen[rc]=(sumlen[rc]*addlen[root]%mod*addlen[root]%mod)%mod; addl[root]=addr[root]=0; addlen[root]=1; } } void update(int ql, int qr, ll val, int l, int r, int root){ int mid = (l+r)>>1; if(ql<=l&&r<=qr){ sum[root]=(10*sum[root]%mod+(r-l+1)*val%mod+val*sumlen[root]%mod)%mod; sumlen[root]=sumlen[root]*100%mod; addl[root]=(addl[root]+val*addlen[root])%mod; addr[root]=(addr[root]*10+val)%mod; addlen[root]=(addlen[root]*10)%mod; return; } pushdown(l,r,root); if(ql<=mid)update(ql,qr,val,lson); if(qr>mid)update(ql,qr,val,rson); sum[root]=(sum[lc]+sum[rc])%mod; sumlen[root]=(sumlen[lc]+sumlen[rc])%mod; return; } ll query(int ql, int qr, int l, int r, int root){ int mid = (l+r)>>1; if(ql<=l&&r<=qr)return sum[root]%mod; ll ans = 0; pushdown(l,r,root); if(ql<=mid)ans+=query(ql,qr,lson); if(qr>mid)ans+=query(ql,qr,rson); return ans%mod; } char op[5]; int main(){ scanf("%d", &t); div10=fp(10,mod-2)%mod; for(int ncase = 1; ncase <= t; ncase++){ scanf("%d %d", &n, &m); build(1,n,1); printf("Case %d:\n",ncase); while(m--){ ll w; int x, y; scanf("%s",op+1); scanf("%d %d", &x, &y); if(op[1]=='w'){ scanf("%lld", &w); update(x, y, w, 1, n, 1); } else{ printf("%lld\n",query(x,y,1,n,1)%mod); } } } return 0; } /* 2 3 3 wrap 1 3 1 wrap 2 4 3 query 1 2 4 4 wrap 1 3 0 wrap 2 4 3 query 1 4 query 2 3 1 4 4 wrap 1 3 0 wrap 2 4 3 3 4 4 wrap 1 4 2 wrap 1 4 3 wrap 1 4 1 wrap 2 4 6 3 2 wrap 1 3 0 wrap 2 2 1 5 3 wrap 1 5 1 wrap 2 6 0 wrap 3 5 2 */