Ocean的礼物(线段树单点修改)
題目鏈接:http://oj.ismdeep.com/contest/Problem?id=1284&pid=0
A: Ocean的禮物
Time Limit: 5 s ???? Memory Limit: 128 MB ???? Submit My StatusProblem Description
?????? 皇家理工存在一段很神奇的路段,這段路由nn 個格子組成,每個格子都有一個數字,你可以走這段路的任意一段。這段路的神奇之處就在于,如果你所處的這個格子數字和你經過的前一個格子數字不相同的話,你就可以獲得一個禮物(初始一定可以獲得禮物)。現在Ocean想知道,給定任意路段的左邊界和右邊界,問若走這段路可以獲得多少禮物。不過幸運的是,Ocean很快就解決了,并且獲得了大量的禮物。玩的十分開心。但是有一天,這段路神奇的發生了改變。它不但會給你禮物。它還可能隨時的改變其任意某處的格子上的數字。這下Ocean可就犯愁了,他想知道任意一段路可以獲得的禮物是多少。聰明的你可以幫下他嗎?
Input
第一行輸入一個整數nn ,代表格子數。(1≤n≤106)(1≤n≤106)
第二行輸入nn 個整數xx 。(1≤x≤108)(1≤x≤108)
第三行輸入一個整數mm ,代表mm 次操作。(1≤m≤2?105)(1≤m≤2?105)
接下來第四行到3+m3+m 行每行33 個數op,x,yop,x,y 。
若op=1op=1 則把xx 處的數修改為yy 。(1≤x≤n,1≤y≤108)(1≤x≤n,1≤y≤108)
若op=2op=2 ,詢問區間[x,y][x,y] 內可以獲得的禮物數。(1≤x≤y≤n)(1≤x≤y≤n)
Output
對于每個詢問輸出一個整數,代表可以獲得的禮物數
Sample Input
6 1 2 3 4 5 6 4 2 1 6 1 2 3 2 2 3 2 3 4Sample Output
6 1 2Hint
解題思路:做這題之前表示還沒看過線段樹,后來比賽完了,隨便看了一篇關于線段樹區間修改的文章,感覺可以運用到這題,然后我就硬生生把這題單點修改的問題當做區間修改來寫了,就是每次修改點的時候判斷與前面那個數是否一致,后面那個數是否一致,原來那個數,與前面那個數是否一致,與后面那個數是否一致,一共是16種情況,賊復雜,沒辦法還不太會用,還好時間限制比較松,運行了2000ms,AC了,先看下我的垃圾代碼吧。。。下面再上正確代碼。
具體看代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt*2+1 #define pushup(rt) t[rt]=t[rt*2]+t[rt*2+1] typedef long long ll; const ll mod=1000000007; const ll maxn=1000007; int k=1; ll t[maxn*4],lazy[maxn*4],a[maxn*4],num[maxn];void build(int l,int r,int rt) {lazy[rt] = 0;if(l==r){t[rt]=a[k++];//scanf("%lld",&t[rt]);return ;}int m = (l+r)/2;build(lson);build(rson);pushup(rt); } void pushdown(int l,int r,int rt) {if(lazy[rt]){lazy[rt*2] += lazy[rt];lazy[rt*2+1] += lazy[rt];t[rt*2] += l*lazy[rt];t[rt*2+1] += r*lazy[rt];lazy[rt] = 0;} } void update(int L,int R,int C,int l,int r,int rt) {if(L<=l&&r<=R){t[rt] += (r-l+1)*C;lazy[rt] += C;return ;}int m = (l+r)/2;pushdown(m-l+1,r-m,rt);if(L<=m)update(L,R,C,lson);if(R>m)update(L,R,C,rson);pushup(rt); } ll query(int L,int R,int l,int r,int rt) {if(L<=l&&r<=R)return t[rt];int m = (l+r)/2;pushdown(m-l+1,r-m,rt);ll ans = 0;if(L<=m)ans += query(L,R,lson);if(R>m)ans += query(L,R,rson);return ans; }int n,q,op,x; ll y;int main() {while(scanf("%d",&n)!=EOF){a[1]=1;for(int i=1;i<=n;i++){scanf("%lld",&num[i]);if(i>1&&num[i]!=num[i-1])a[i]=1;if(i>1&&num[i]==num[i-1])a[i]=0;}num[0]=num[n+1]=0;build(1,n,1);scanf("%d",&q);while(q--){scanf("%d",&op);scanf("%d%lld",&x,&y);if(op==1){if(num[x]!=num[x-1]&&num[x]!=num[x+1]){if(y!=num[x-1]&&y!=num[x+1])continue;else if(y==num[x-1]&&y!=num[x+1])update(x,x,-1,1,n,1);else if(y!=num[x-1]&&y==num[x+1])update(x+1,x+1,-1,1,n,1);elseupdate(x,x+1,-1,1,n,1);}else if(num[x]==num[x-1]&&num[x]!=num[x+1]){if(y!=num[x-1]&&y!=num[x+1])update(x,x,1,1,n,1);else if(y==num[x-1]&&y!=num[x+1])continue;else if(y!=num[x-1]&&y==num[x+1]){update(x,x,1,1,n,1);update(x+1,x+1,-1,1,n,1);}elseupdate(x+1,x+1,-1,1,n,1);}else if(num[x]!=num[x-1]&&num[x]==num[x+1]){if(y!=num[x-1]&&y!=num[x+1])update(x+1,x+1,1,1,n,1);else if(y==num[x-1]&&y!=num[x+1]){update(x,x,-1,1,n,1);update(x+1,x+1,1,1,n,1);}else if(y!=num[x-1]&&y==num[x+1])continue;elseupdate(x,x,-1,1,n,1);}else{if(y!=num[x-1]&&y!=num[x+1])update(x,x+1,1,1,n,1);else if(y==num[x-1]&&y!=num[x+1])update(x+1,x+1,1,1,n,1);else if(y!=num[x-1]&&y==num[x+1])update(x,x,1,1,n,1);elsecontinue;}num[x]=y;}else{if(num[x]==num[x-1])printf("%lld\n",query(x,y,1,n,1)+1);elseprintf("%lld\n",query(x,y,1,n,1));}}}return 0; }正確思路:構建線段樹時,一個節點保存三個信息,所在區間的不同的線段個數,區間的左邊界和右 邊界,合并區間時,比較左子區間的右邊界和右子區間的左邊界,若相等,就是兩個區間 的不相同的線段樹個數相加減一。
正確代碼:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <vector> #include <queue> #include <stack> #include <cstdlib> #include <iomanip> #include <cmath> #include <cassert> #include <ctime> #include <map> #include <set> using namespace std; #pragma comment(linker, "/stck:1024000000,1024000000") #pragma GCC diagnostic error "-std=c++11" #define lowbit(x) (x&(-x)) #define max(x,y) (x>=y?x:y) #define min(x,y) (x<=y?x:y) #define MAX 100000000000000000 #define MOD 1000000007 #define esp 1e-9 #define pi acos(-1.0) #define ei exp(1) #define PI 3.1415926535897932384626433832 #define ios() ios::sync_with_stdio(true) #define INF 0x3f3f3f3f #define mem(a) (memset(a,0,sizeof(a))) typedef long long ll; const int maxn=1000006; int tree[maxn<<2][3]; int n,m,x,y,op; void pushup(int root) {tree[root][2]=tree[root<<1][2]+tree[root<<1|1][2];tree[root][0]=tree[root<<1][0];tree[root][1]=tree[root<<1|1][1];if(tree[root<<1][1]==tree[root<<1|1][0]) tree[root][2]--;//合并區間時,比較左子區間的右邊界和右子區間的左邊界,若相//等,就是兩個區間 的不相同的線段樹個數相加減一 } void build(int l,int r,int root) {if(l==r){scanf("%d",&tree[root][0]); //tree[root][0]區間的左邊界tree[root][1]=tree[root][0]; //tree[root][1]區間的右邊界tree[root][2]=1; //tree[root][2]所在區間不同的線段個數return ;}int mid=l+r>>1;build(l,mid,root<<1);build(mid+1,r,root<<1|1);pushup(root); } void update(int pos,int val,int l,int r,int root) {if(l==r){tree[root][0]=tree[root][1]=val;return ;}int mid=l+r>>1;if(pos<=mid) update(pos,val,l,mid,root<<1);else update(pos,val,mid+1,r,root<<1|1);pushup(root); } int query(int L,int R,int l,int r,int root) {if(L<=l && R>=r) return tree[root][2];int ans=0,mid=l+r>>1;if(L<=mid) ans+=query(L,R,l,mid,root<<1);if(R>mid) ans+=query(L,R,mid+1,r,root<<1|1);if(L<=mid && R>mid && tree[root<<1][1]==tree[root<<1|1][0]) ans--;return ans; } int main() {scanf("%d",&n);build(1,n,1);scanf("%d",&m);while(m--){scanf("%d%d%d",&op,&x,&y);if(op==1) update(x,y,1,n,1);else printf("%d\n",query(x,y,1,n,1));}return 0; }?
轉載于:https://www.cnblogs.com/zjl192628928/p/9473191.html
總結
以上是生活随笔為你收集整理的Ocean的礼物(线段树单点修改)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis 源码走读(二)对象系统
- 下一篇: 如何获得select被选中option的