hdu 4578 線段樹多重操作
阿新 • • 發佈:2019-02-17
這道題一看題意很簡單,一顆裸線段樹,看似水題卻不水,因為有很多細節問題得注意,如果沒處理好就會各種TLE。
題意:四種操作,(1)op==1 [l,r]之間的所有數都增加一個數d.
(2) op==2 [l,r]之間的所有數都乘上一個數d.
(3) op==3 [l,r]之間的所有數都變為一個數d
(4) op==4 [l,r]計算 所有數的d次方的和
<span style="font-family: Arial, Helvetica, sans-serif;">思路: 可以用三種標記 三種操作,每次更新都不要更新到底,稍微標記一下即可。。。我第一次寫的時候是三個操作三組函式,然後TLE。</span>
<span style="font-family: Arial, Helvetica, sans-serif;">昨天晚上學會了一種方法 就是隻用一個變數標記即可(num),當num==-1表示 這個區間的數不一定相等,當num!=-1表示區間內的所有數都相同。</span>
<span style="font-family: Arial, Helvetica, sans-serif;">而且還得注意該取模的地方儘量都取模~</span>
<pre name="code" class="cpp">#include <iostream> #include <stdio.h> #include <cmath> #include <string.h> const int MAX=101000; const int mod=10007; using namespace std; struct node { int l,r,num; }st[MAX*4]; void build(int v,int l,int r) { st[v].l=l; st[v].r=r; st[v].num=0; if(l==r)return; int mid=(l+r)/2; build(2*v,l,mid); build(2*v+1,mid+1,r); } int pow(int a,int b) { int ans=1; for(int i=1;i<=b;i++) ans=ans*a%mod; return ans%mod; } void updata(int v,int op,int l,int r,int p) { if(l<=st[v].l&&st[v].r<=r&&(st[v].num!=-1||op==3)) //如果把op==3去掉,TLE { if(op==3) //只要op==3,不管num是多少,直接覆蓋,也就是op==3的優先順序最高,對應與相應的區間 { st[v].num=p; } else if(op==2) { st[v].num=st[v].num*p%mod; } else if(op==1) { st[v].num=(st[v].num+p)%mod; } return; } if(st[v].num!=-1) //這裡相當於pushdown(),就是要改變當前區間的子區間時,將當前區間的屬性給左右孩子 { st[v*2].num=st[v].num; st[v*2+1].num=st[v].num; st[v].num=-1; } int mid=(st[v].l+st[v].r)/2; if(r<=mid)updata(2*v,op,l,r,p); else if(l>mid)updata(2*v+1,op,l,r,p); else { updata(2*v,op,l,mid,p); updata(2*v+1,op,mid+1,r,p); } } int getsum(int v,int l,int r,int p) { if(l<=st[v].l&&st[v].r<=r&&st[v].num!=-1) { return (r-l+1)*pow(st[v].num,p)%mod; } if(st[v].num!=-1) { st[v*2].num=st[v].num; st[v*2+1].num=st[v].num; st[v].num=-1; } int mid=(st[v].l+st[v].r)/2; if(r<=mid)return getsum(2*v,l,r,p); else if(l>mid)return getsum(2*v+1,l,r,p); else return (getsum(2*v,l,mid,p)+getsum(2*v+1,mid+1,r,p))%mod; } int main() { int n,m; int op,x,y,p; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0)break; build(1,1,n); for(int i=0;i<m;i++) { scanf("%d%d%d%d",&op,&x,&y,&p); if(op==4) printf("%d\n",getsum(1,x,y,p)); else updata(1,op,x,y,p); } } return 0; }