hdu 4638 Group 單點修改和離線線段樹

2021-06-26 01:49:40 字數 1467 閱讀 9603

跟hdu4630如出一轍,但是思想上還是要有特別技巧

對於[l,r]上的數a[i],我們給乙個標記mark[i],表示第第i個數屬於某個連續區間

初始時都賦值為0

pos[a[i]] 表示值為a[i]的數所在位置

當遇到情況 a[i]+1 或 a[i]-1 曾經 出現過時,mark[ pos[a[i]-1] ] = 1 或 mark[ pos[a[i]+1] ] = 1

最終結果 = (r-l+1) - sum(mark[l...r]) 

可以用線段樹來儲存mark,維護sum

但這種演算法的正確性**於我們從左到右遞推,而詢問不會從左到右這麼巧

所以我們要離線

#include #include #include #include #include #include #include #include #include using namespace std;

#define inf 1e9

#define maxn 100010

#define rep(i,x,y) for(int i=x;i<=y;i++)

#define mset(x) memset(x,0,sizeof(x))

const int maxnode = 100010*4;

int x, x1, x2, res;

struct intervaltree

void update(int o, int l, int r)

int mid = l+(r-l)/2, lc = 2*o, rc = 2*o+1;

if(x<=mid) update(lc, l, mid);

else update(rc, mid+1, r);

sumv[o] = sumv[lc] + sumv[rc];

} void query(int o, int l, int r)

int mid = l+(r-l)/2, lc = 2*o, rc = 2*o+1;

if(x1<=mid) query(lc, l, mid);

if(x2>mid) query(rc, mid+1, r);

}}tree;

int t, n, m;

int a[maxn];

struct operate

sort(op+1, op+m+1);

memset(pos, -1, sizeof(pos));

tree.init();

int qcnt=1;

rep(i,1,n)

if( pos[a[i]+1]>=0 )

while(qcnt<=m && op[qcnt].r==i)

if(qcnt>m) break;

pos[a[i]] = i;

} rep(i,1,m) printf("%d\n", ans[i]);

} return 0;

}

hdu4638 Group(樹狀陣列)

題目大意 給乙個1 n的排列,然後詢問 x,y 區間中有多少個連續的段。如給乙個3 1 2 5 4,查詢是2 4,那麼就是問1 2 5中有多少個連續的串,一共有兩個串,1 2為乙個串,5為乙個串 若查詢是2 5,則問的是1 2 5 4中有多少個連續的串,一共有兩個串,1 2為乙個串,4 5 為乙個串...

hdu 4638 Group 樹狀陣列

題意 找到區間裡有多少組連續數字串 分析 思路 顯然,我們要使得value最大,就要盡量將連續的id分在一組,所以問題轉化為求乙個區間中連續id區間的個數。我們從左往右掃瞄,依次考慮右端點為i的詢問,設dp l 為區間 l,i 的連續區間個數,po i 為i出現的位置,若還未出現,則為0,設我們當前...

HDU 4638 Group 樹狀陣列

詢問一段區間裡的數能組成多少段連續的數。先考慮從左往右乙個數乙個數新增,考慮當前新增了i 1個數的答案是x,那麼可以看出新增完i個數後的答案是根據a i 1和a i 1是否已經新增而定的 如果a i 1或者a i 1已經新增乙個,則段數不變,如果都沒新增則段數加1,如果都新增了則段數減1。設v i ...