POJ 3468
连续交了几次还WA,错误点比较多
代码+解释,盲打就指日可待啦
/*线段树之连续区间更新和询问*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 100001
#define LL long long
LL a[N], tree[3*N], inc[3*N];
void add(int node, int beg, int end, int l, int r, LL d)
{
if(r < beg || l > end || l > r) return;
/*l>r起到剪枝作用*/
if(l <= beg && end <= r)
{
inc[node] += d;
return;
}
tree[node] += (r-l+1)*d;
/*被更改区间的父区间值被修改,容易忘*/
int mid = (beg+end) >> 1;
add(node*2, beg, mid, l, min(r, mid), d);
add(node*2+1, mid+1, end, max(mid+1, l), r, d);
/*min,max为了简化而设定,可行*/
}
void build(int node, int l, int r)
{
if(l == r)
tree[node] = a[l];
else{
int mid = (l + r) >> 1;
build(node*2, l, mid);
build(node*2+1, mid+1, r);
tree[node] = tree[node*2] + tree[node*2+1];
}
}
/*add与query的结构相似*/
LL query(int node, int beg, int end, int l, int r)
{
if(r < beg || l > end || l > r) return 0;
if(l <= beg && end <= r)
return tree[node] + (end-beg+1)*inc[node];
/*当询问区间被覆盖,则不需继续往下更新,直接返回结果*/
int mid = (beg+end) >> 1;
if(inc[node])//剪枝
{
/*向下更新子区间,inc是对一个小区间所有数而言的*/
tree[node] += inc[node]*(end-beg+1);
add(node*2, beg, mid, beg, mid, inc[node]);
add(node*2+1, mid+1, end, mid+1, end, inc[node]);
inc[node] = 0;
}
return query(node*2, beg, mid, l, min(mid, r))
+ query(node*2+1, mid+1, end, max(mid+1,l), r);
}
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
for(int i = 0;i < n;i++)
scanf("%I64d", &a[i]);
memset(inc, 0, sizeof(inc));
build(1, 0, n-1);
char str[10];
while(m--)
{
int l, r, d;
scanf("%s%d%d", str, &l, &r);
if(str[0] == 'Q')
{
LL ans = query(1, 0, n-1, l-1, r-1);
printf("%I64d\n", ans);
}
else
{
scanf("%d", &d);
add(1, 0, n-1, l-1, r-1, d);
}
}
}
return 0;
}
POJ 1151
这题坑了3天了,终于AC,大概花了半天想清楚了原理,但一直手残敲不出来。输出中间过程反而不太容易分析出来,还是应该定义好每个变量的含义。
cover是一个区间被完全覆盖时,计数覆盖了几重。子区间不用继承父区间的重数,否则在更新时会出错!(这点坑了一天)
has是一个区间完全没被覆盖置为0,否则只要沾边就置为1.当子区间has为1时,父区间has必定为1.同时该区间cover>0时,has必为1.
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 105
#define eps 1e-8
int n;
double a[N*2], ans, len;
int cover[N*8], has[N*8], all;
struct node
{
double x1, y1, x2, y2;
int flag;
}s[N*2];
void build(int rt, int l, int r)
{
all++;
cover[rt] = has[rt] = 0;
if(r != l)
{
int mid = l+r >> 1;
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
}
}
int get(double x)
{
for(int i = 0;i < 2*n;i++)
if(fabs(x-a[i]) < eps)
return i;
}
void update(int rt, int beg, int end, int l, int r, int flag)
{
if(l > r || end < l || r < beg) return;
if(l <= beg && end <= r)
{
cover[rt] += flag;
if(beg == end)
has[rt] = cover[rt] ? 1 : 0;
else
has[rt] = cover[rt]||has[rt<<1]||has[rt<<1|1] ? 1 : 0;
return;
}
int mid = beg + end >> 1;
update(rt<<1, beg, mid, l, min(r, mid), flag);
update(rt<<1|1, mid+1, end, max(mid+1, l), r, flag);
has[rt] = cover[rt]||has[rt<<1]||has[rt<<1|1] ? 1 : 0;
}
double query(int rt, int l, int r)
{
if(!has[rt])
return 0;
if(cover[rt])
return a[r+1]-a[l];
int mid = l+r >> 1;
return query(rt<<1, l, mid) +
query(rt<<1|1, mid+1, r);
}
bool cmp(node p, node q)
{
return p.y1 < q.y1;
}
void pr()
{
for(int i = 1;i <= all;i++)
printf("%d ", i);
printf("\n");
for(int i = 1;i <= all;i++)
printf("%d ", cover[i]);
printf("\n");
for(int i = 1;i <= all;i++)
printf("%d ", has[i]);
printf("\n");
}
int main()
{
int o = 0;
while(scanf("%d", &n), n)
{
ans = 0;
for(int i = 0;i < n;i++)
{
int d = 2*i;
scanf("%lf%lf", &s[d].x1, &s[d].y1);
scanf("%lf%lf", &s[d+1].x2, &s[d+1].y2);
s[d].x2 = s[d+1].x2;
s[d].y2 = s[d].y1;
s[d+1].x1 = s[d].x1;
s[d+1].y1 = s[d+1].y2;
a[d] = s[d].x1;
a[d+1] = s[d].x2;
s[d].flag = 1;
s[d+1].flag = -1;
}
all = 0;
sort(a, a+2*n);
sort(s, s+2*n, cmp);
build(1, 0, 2*n-2);
for(int i = 0;i < 2*n-1;i++)
{
int l = get(s[i].x1), r = get(s[i].x2)-1;
//printf("l= %d r=%d\n", l, r);
update(1, 0, 2*n-2, l, r, s[i].flag);
len = query(1, 0, 2*n-2);
ans += len*(s[i+1].y1-s[i].y1);
//pr();
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", ++o, ans);
}
return 0;
}
POJ 3321
乍一眼看是多叉树,先把它化为能用线段树解决的问题,先用dfs遍历一遍。
树状数组的性质:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 110000
typedef vector<int> VCI;
vector<VCI> T(N); //vector这样写才能过,否则T
//using vector_type = std::vector<int>; C++11版本
int lef[N], rig[N], n, cnt, a[2*N], C[2*N], L[2*N];
void init()
{
for(int i = 0;i <= n;i++)
T[i].clear();
for(int i = 1;i < n;i++)
{
int u, v;
scanf("%d%d", &u, &v);
T[u].push_back(v);
}
cnt = 0;
}
void dfs(int x)
{
lef[x] = ++cnt;
for(int i = 0;i < T[x].size();i++)
dfs(T[x][i]);
rig[x] = ++cnt;
a[lef[x]] = a[rig[x]] = 1;
}
void set()
{
for(int x = 1;x <= 2*N;x++)
L[x] = x&(x^(x-1));
}
void give()
{
for(int i = 1;i <= 2*n;i++)
C[i] = L[i];
}
int sum(int x)
{
int r = 0;
while(x > 0)
{
r += C[x];
x -= L[x];
}
return r;
}
void modify(int x, int y)
{
int i = x;
while(i <= 2*n)
{
C[i] += - a[x] + y;
i += L[i];
}
a[x] = y;
}
int main()
{
set();
while(~scanf("%d", &n))
{
init();
dfs(1);
give();
int m;
scanf("%d", &m);
while(m--)
{
char str[2];
int x;
scanf("%s%d", str, &x);
if(str[0] == 'Q')
printf("%d\n", (sum(rig[x])-sum(lef[x]-1))/2);
else{
modify(rig[x], 1-a[rig[x]]);
modify(lef[x], 1-a[lef[x]]);
}
}
}
return 0;
}
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1100
int a[N][N], n, C[N][N], L[N];
void set()
{
for(int i = 0;i < N;i++)
L[i] = i&((i-1)^i);
}
void init()
{
scanf("%d", &n);
memset(a, 0, sizeof(a));
memset(C, 0, sizeof(C));
}
void add()
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
x++; y++;
int t = max(0, a[x][y]+z)-a[x][y];
a[x][y] += z;
while(x <= n)
{
int ty = y;
while(ty <= n)
{
C[x][ty] += t;
ty += L[ty];
}
x += L[x];
}
}
int sum(int x, int y)
{
int r = 0;
while(x > 0)
{
int ty = y;
while(ty > 0)
{
r += C[x][ty];
ty -= L[ty];
}
x -= L[x];
}
return r;
}
void query()
{
int x1, y1, x2, y2;
scanf("%d%d%d%d",&x1, &y1, &x2, &y2);
x2++; y2++;
int ans = sum(x2,y2)-sum(x1,y2)-sum(x2,y1)+sum(x1,y1);
printf("%d\n", ans);
}
int main()
{
set();
int command;
while(~scanf("%d", &command))
{
int st = 0;
switch(command)
{
case 0: init(); break;
case 1: add(); break;
case 2: query(); break;
default: st = 1; break;
}
if(st)
break;
}
return 0;
}
POJ 2155
树套树,子区间不需继承父区间的标记。在询问时,无需动态向下更新,只需沿路根据标记算出对应的值。
参数较多,一不小心会打错……
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1100
int n, tree[3*N][3*N], ans;
void up(int xrt, int yrt, int yb, int ye, int yl, int yr)
{
if(yr < yb || ye < yl || yl > yr) return;
if(yl <= yb && ye <= yr)
{
tree[xrt][yrt] = !tree[xrt][yrt];
return;
}
int ym = yb+ye >> 1;
up(xrt, yrt<<1, yb, ym, yl, min(ym, yr));
up(xrt, yrt<<1|1, ym+1, ye, max(ym+1, yl), yr);
}
void update(int xrt, int xb, int xe, int xl, int xr, int yl, int yr)
{
if(xr < xb || xe < xl || xl > xr) return;
if(xl <= xb && xe <= xr)
{
up(xrt, 1, 1, n, yl, yr);
return;
}
int xm = xb+xe >> 1;
update(xrt<<1, xb, xm, xl, min(xr, xm), yl, yr);
update(xrt<<1|1, xm+1, xe, max(xm+1, xl), xr, yl, yr);
}
void que(int xrt, int yrt, int yb, int ye, int yl, int yr)
{
if(yr < yb || ye < yl || yl > yr) return;
ans ^= tree[xrt][yrt];
//容易漏啊!从根到子区间一路上的标记都作用到上面,属于第二维
if(yl <= yb && ye <= yr) return;
int ym = yb+ye >> 1;
que(xrt, yrt<<1, yb, ym, yl, min(ym, yr));
que(xrt, yrt<<1|1, ym+1, ye, max(ym+1, yl), yr);
}
void query(int xrt, int xb, int xe, int xl, int xr, int yl, int yr)
{
if(xr < xb || xe < xl || xl > xr) return;
que(xrt, 1, 1, n, yl, yr);
//不甚理解,也是通往子区间的标记,属于第一维的
if(xl <= xb && xe <= xr) return;
int xm = xb+xe >> 1;
query(xrt<<1, xb, xm, xl, min(xr, xm), yl, yr);
query(xrt<<1|1, xm+1, xe, max(xm+1, xl), xr, yl, yr);
}
int pr()
{
for(int i = 1;i <= 3*n;i++)
for(int j = 1;j <= 3*n;j++)
printf("%d%c", tree[i][j], " \n"[j==3*n]);
printf("\n");
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int m;
while(~scanf("%d%d", &n, &m))
{
memset(tree, 0, sizeof(tree));
while(m--)
{
char str[10];
scanf("%s", str);
switch(str[0])
{
case 'C':
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
update(1, 1, n, x1, x2, y1, y2);
break;
case 'Q':
int x, y;
scanf("%d%d", &x, &y);
ans = 0;
query(1, 1, n, x, x, y, y);
printf("%d\n", ans);
break;
}
// pr();
}
if(T)
printf("\n");
}
}
return 0;
}