hdu4578线段树维护平方和,立方和(加,乘,赋值)或者珂朵莉树
一开始我用线段树去做,结果debug了一个下午和晚上QAQ,后来学了珂朵莉树,发现这题原来可以这么简单的写,发出两个代码对比一下
#include<bits/stdc++.h> #define ll unsigned long long using namespace std; const ll INFINITE = INT_MAX; const ll MAXNUM = 100005*4; ll mod=10007; struct SegTreeNode { ll p1,p2,p3; ll l,r; ll addMark;//加数标记 ll mulMark;//乘数标记 ll assignMark;//赋值标记 } segTree[MAXNUM]; void pushup(ll root) { segTree[root].p1 = (segTree[root*2].p1 + segTree[root*2+1].p1)%mod; segTree[root].p2 = (segTree[root*2].p2 + segTree[root*2+1].p2)%mod; segTree[root].p3 = (segTree[root*2].p3 + segTree[root*2+1].p3)%mod; } void build(ll root, ll arr[], ll L, ll R) { segTree[root].addMark = 0; segTree[root].mulMark = 1; segTree[root].assignMark = 0; segTree[root].l=L; segTree[root].r=R; if(L == R)//叶子节点 { segTree[root].p1 = segTree[root].p2=segTree[root].p3=0; } else { ll mid = (L + R) / 2; build(root*2, arr, L, mid); build(root*2+1, arr, mid+1, R); pushup(root); } } void pushDown(ll root) { SegTreeNode &rt=segTree[root]; SegTreeNode &lson=segTree[root*2]; SegTreeNode &rson=segTree[root*2+1]; ll len1=(lson.r-lson.l+1)%mod; ll len2=(rson.r-rson.l+1)%mod; if(rt.assignMark) { rt.assignMark%=mod; lson.assignMark =rson.assignMark= rt.assignMark%mod; lson.addMark=rson.addMark=0; lson.mulMark=rson.mulMark=1; lson.p1=(len1*rt.assignMark)%mod; lson.p2=((len1*rt.assignMark)%mod*rt.assignMark)%mod; lson.p3=(((len1*rt.assignMark)%mod*rt.assignMark)%mod*rt.assignMark)%mod; rson.p1=(len2*rt.assignMark)%mod; rson.p2=((len2*rt.assignMark)%mod*rt.assignMark)%mod; rson.p3=(((len2*rt.assignMark)%mod*rt.assignMark)%mod*rt.assignMark)%mod; rt.assignMark = 0; } if(rt.mulMark != 1) { rt.mulMark%=mod; lson.mulMark = (lson.mulMark*rt.mulMark)%mod; rson.mulMark = (rson.mulMark*rt.mulMark)%mod; if(lson.addMark)lson.addMark=(lson.addMark*rt.mulMark)%mod; if(rson.addMark)rson.addMark=(rson.addMark*rt.mulMark)%mod; lson.p1=(lson.p1*rt.mulMark)%mod; lson.p2=((lson.p2*rt.mulMark)%mod*rt.mulMark)%mod; lson.p3=(lson.p3*(((rt.mulMark*rt.mulMark)%mod*rt.mulMark)%mod))%mod; rson.p1=(rson.p1*rt.mulMark)%mod; rson.p2=((rson.p2*rt.mulMark)%mod*rt.mulMark)%mod; rson.p3=(rson.p3*(((rt.mulMark*rt.mulMark)%mod*rt.mulMark)%mod))%mod; rt.mulMark = 1; } if(rt.addMark) { rt.addMark%=mod; lson.addMark = (lson.addMark+rt.addMark)%mod; rson.addMark = (rson.addMark+rt.addMark)%mod; lson.p3 = ((lson.p3+(((len1*rt.addMark)%mod*rt.addMark)%mod*rt.addMark)%mod)%mod+(((3*rt.addMark)%mod)*(((lson.p1*rt.addMark)%mod+lson.p2)%mod))%mod)%mod; lson.p2 = ((lson.p2+ ((len1*rt.addMark)%mod*rt.addMark)%mod)%mod+((2*rt.addMark)%mod*lson.p1)%mod)%mod; lson.p1 =( lson.p1+ (len1*rt.addMark)%mod)%mod; rson.p3 = ((rson.p3+(((len2*rt.addMark)%mod*rt.addMark)%mod*rt.addMark)%mod)%mod+(((3*rt.addMark)%mod)*(((rson.p1*rt.addMark)%mod+rson.p2)%mod))%mod)%mod; rson.p2 = ((rson.p2+ ((len2*rt.addMark)%mod*rt.addMark)%mod)%mod+((2*rt.addMark)%mod*rson.p1)%mod)%mod; rson.p1 =(rson.p1+ (len2*rt.addMark)%mod)%mod; rt.addMark = 0; } } ll query(ll rt,ll L, ll R,ll p) { if(L == segTree[rt].l&& segTree[rt].r==R) { if(p==1)return segTree[rt].p1%mod; if(p==2)return segTree[rt].p2%mod; if(p==3)return segTree[rt].p3%mod; } pushDown(rt); //----延迟标志域向下传递 ll mid = (segTree[rt].l+segTree[rt].r)/2; if(R <= mid) return query(rt*2,L, R,p); else if(L > mid) return query(rt*2+1,L, R,p); else return (query(rt*2,L,mid,p)+query(rt*2+1,mid+1, R,p))%mod; } void update(ll rt, ll L, ll R, ll c,ll p) { if(L == segTree[rt].l&& segTree[rt].r==R) { SegTreeNode &root=segTree[rt]; SegTreeNode &lson=segTree[rt*2]; SegTreeNode &rson=segTree[rt*2+1]; ll len=(root.r-root.l+1)%mod; if(p==1) { root.addMark = (root.addMark+c)%mod; root.p3 =((root.p3+(((len*c)%mod*c)%mod*c)%mod)%mod+(((3*c)%mod)*(((root.p1*c)%mod+root.p2)%mod))%mod)%mod; root.p2 =((root.p2+((len*c)%mod*c)%mod)%mod+((2*root.p1)%mod*c)%mod)%mod; root.p1 =(root.p1+ (len*c)%mod)%mod; } else if(p==2) { root.mulMark = (root.mulMark*c)%mod; if(root.addMark)root.addMark=(root.addMark*c)%mod; root.p1 = (root.p1*c)%mod; root.p2 = ((root.p2*c)%mod*c)%mod; root.p3 = (((root.p3*c)%mod*c)%mod*c)%mod; } else if(p==3) { root.addMark = 0; root.mulMark = 1; root.assignMark=c; root.p1 = (len*c)%mod; root.p2 = ((len*c)%mod*c)%mod; root.p3 = (((len*c)%mod*c)%mod*c)%mod; } return ; } pushDown(rt); //延迟标记向下传递 ll mid = (segTree[rt].l+segTree[rt].r)/2; if(R <= mid) update(rt*2,L, R, c,p); else if(L > mid) update(rt*2+1,L, R, c,p); else update(rt<<1, L, mid, c, p),update(rt*2+1,mid+1, R, c,p); pushup(rt); } int main() { ll n,m; while(scanf("%llu%llu",&n,&m)&&n+m) { build(1,NULL,1,n); while(m--) { ll op,x,y,p; scanf("%llu%llu%llu%llu",&op,&x,&y,&p); if(op==4) { ll ans=query(1,x,y,p); printf("%llu\n",ans); } else update(1,x,y,p,op); } } return 0; }
下面是用珂朵莉树的写法:
#include<bits/stdc++.h> #define ll long long #define IT set<node>::iterator #define I_like_Chtholly_forever 10007 using namespace std; struct node { ll l,r; mutable ll val; node(ll L,ll R=-1,ll V=0): l(L), r(R), val(V) {} bool operator < (const node& tt)const { return l<tt.l; //以区间左端点排序 } }; set<node> st; IT split(ll pos) { IT it=st.lower_bound(node(pos));//二分找到第一个左端点不小于pos的区间 if(it!=st.end()&&it->l==pos) return it;//pos本身就是某个区间的左端点,不用分裂 --it;//否则上一个区间才是包含pos的区间 ll l=it->l,r=it->r,val=it->val; st.erase(it);//删除原结点 st.insert(node(l,pos-1,val)); return st.insert(node(pos,r,val)).first;//这里.first返回的是迭代器 } void assign_val(ll l,ll r,ll val) { IT itr=split(r+1),itl=split(l); st.erase(itl,itr); st.insert(node(l,r,val)); } void add(ll l,ll r,ll val) { IT itr=split(r+1),itl=split(l); for(; itl!=itr; ++itl) { itl->val=(itl->val+val)%I_like_Chtholly_forever; } } void mul(ll l,ll r,ll val) { IT itr=split(r+1),itl=split(l); for(; itl!=itr; ++itl) { itl->val=(itl->val*val)%I_like_Chtholly_forever; } } ll quick_pow(ll a, ll b, ll mod) { ll res = 1; ll ans = a % mod; while (b) { if (b&1) res = res * ans % mod; ans = ans * ans % mod; b>>=1; } return res; } ll sum(ll l,ll r,ll en,ll mod) { IT itr=split(r+1),itl=split(l); ll res=0; for(; itl!=itr; ++itl) { res = (res + (itl->r-itl->l +1) * quick_pow(itl->val,en,mod))%mod; } return res; }
int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n,m; while(cin>>n>>m&&n&&m) { st.clear(); int op,x,y,c; st.insert(node{1,n,0});
for (int i=0; i<m; i++ ) { cin>>op>>x>>y>>c; if(op==1) { add(x,y,c); } if(op==2) { mul(x,y,c); } if(op==3) { assign_val(x,y,c); } if(op==4) { cout<<sum(x,y,c,I_like_Chtholly_forever)<<endl; } } } return 0; }
可以明显看出珂朵莉树在解决这类问题时候写起来会更简单,但是毕竟是玄学算法,且用且珍惜