hdu 4578 线段树多重操作

本文介绍了一种使用裸线段树解决复杂操作问题的方法,包括四种操作:加法、乘法、赋值及幂运算求和。通过合理利用标记减少不必要的计算,实现了高效的更新与查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题一看题意很简单,一颗裸线段树,看似水题却不水,因为有很多细节问题得注意,如果没处理好就会各种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;
}




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值