線段樹模板:點修改,區間修改
阿新 • • 發佈:2018-12-24
#include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> #include<cmath> #include<bitset> #include<sstream> #include<stack> using namespace std; #define INF 0x7fffffff typedef long long ll; const int maxnode=1<<17; int _sum,_min,_max,op,qL,qR,v; struct IntervalTree { int sumv[maxnode],maxv[maxnode],minv[maxnode],setv[maxnode]; //維護資訊 void maintain(int o,int L,int R){ int lc=2*o,rc=2*o+1; if(R>L){ sumv[o]=sumv[lc]+sumv[rc]; minv[o]=min(minv[lc],minv[rc]); maxv[o]=max(maxv[lc],maxv[rc]); } if(setv[o]>=0){ minv[o]=maxv[o]=setv[o]; sumv[o]=setv[o]*(R-L+1); } } //標記傳遞 void pushdown(int o){ int lc=2*o,rc=2*o+1; if(setv[o]>=0){ //本結點有標記才傳遞。注意本題中set值非負 setv[lc]=setv[rc]=setv[o]; setv[o]=-1;//清除本結點標記 } } //更新資訊 void update(int o,int L,int R){ int lc=2*o,rc=2*o+1; if(qL<=L&&R<=qR){ //標記修改 setv[o]=v; } else{ pushdown(o); int M=L+(R-L)/2; if(qL<=M) update(lc,L,M); else maintain(lc,L,M); if(qR>M) update(rc,M+1,R); else maintain(rc,M+1,R); } maintain(o,L,R); } void query(int o,int L,int R){ if(setv[o]>=0){ //遞迴邊界1:有set標記 _sum+=setv[o]*(min(R,qR)-max(L,qL)+1); _min=min(_min,setv[o]); _max=max(_max,setv[o]); } else if(qL<=L&&qR>=R){ //遞迴邊界2:邊界區間 //此邊界區間沒有被任何set操作影響 _sum+=sumv[o]; _min=min(_min,minv[o]); _max=max(_max,maxv[o]); } else{ //遞迴統計 int M=L+(R-L)/2; if(qL<=M) query(2*o,L,M); if(qR>M) query(2*o+1,M+1,R); } } }; IntervalTree tree; int main() { int n,m; while(scanf("%d%d",&n,&m)==2){ memset(&tree,0,sizeof(tree)); memset(tree.setv,-1,sizeof(tree.setv)); tree.setv[1]=0; while(m--){ scanf("%d%d%d",&op,&qL,&qR); if(op==1){ scanf("%d",&v); tree.update(1,1,n); } else{ _sum=0;_min=INF;_max=-INF; tree.query(1,1,n); printf("%d %d %d\n",_sum,_min,_max); } } } return 0; }