跟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 ...