线段树合集 III

原创 2013年12月01日 23:14:20

hdu 4747 Mex

这道题明显考的是思维方式,线段树作为成段更新求和的辅助。
for i = 1:n
x(i) = 从1到i区间内符合题意的值
end
for i = n:1
y(i) = num(i)下次出现的最近位置
end
res=x(1:n)
for cur = 1:n-1
更新cur+1:y[cur]-1的值,这里用到线段树
res+=结果(cur+1:n)
end
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
/* 
	http://acm.hdu.edu.cn/showproblem.php?pid=4747
*/
const int MAXN = 200010;
const int INF = MAXN<<2;
const int ZERO = -1;
#define LL __int64
#define ll (root<<1)
#define rr (ll|1)
#define lson l,m,ll
#define rson m+1,r,rr
#define mid m=(l+r)>>1
int n, cur;
int data[MAXN], num[MAXN], next[MAXN], pp[MAXN];
struct _MEX
{
	int mx, mn;
	LL sum;
	int sz;
}mex[MAXN*3];
void pushUP(int l, int r, int m, int root)
{
	mex[root].sum = 0;
	mex[root].mx = ZERO; mex[root].mn = INF;
	int z = ll, y = rr;
	if (m >= cur)
	{
		mex[root].sum += mex[z].sum;
		mex[root].mx = max(mex[root].mx, mex[z].mx);
		mex[root].mn = min(mex[root].mn, mex[z].mn);
	}
	if (r >= cur)
	{
		mex[root].sum += mex[y].sum;
		mex[root].mx = max(mex[root].mx, mex[y].mx);
		mex[root].mn = min(mex[root].mn, mex[y].mn);
	}
}
void pushDOWN(int l, int r, int m, int root)
{
	if (mex[root].sz == -1) return;
	int z = ll, y = rr;
	if (m >= cur)
	{
		int k = max(cur, l);
		mex[z].sum = (LL)(m-k+1) * (LL)mex[root].sz;
		mex[z].mx = mex[z].mn = mex[root].sz;
		mex[z].sz = mex[root].sz;
	}
	if (r >= cur)
	{
		int k = max(cur, m+1);
		mex[y].sum = (LL)(r-k+1) * (LL)mex[root].sz;
		mex[y].mx = mex[y].mn = mex[root].sz;
		mex[y].sz = mex[root].sz;
	}
	mex[root].sz = -1;
}
void build(int l, int r, int root)
{
	mex[root].sz = -1;
	if (l == r)
	{
		mex[root].mx = mex[root].mn = data[l];
		mex[root].sum = data[l];
		return;
	}
	int mid;
	build(lson); build(rson);
	pushUP(l,r,m,root);
}
void change(int c, int x, int y, int l, int r, int root)
{
	if (x <= l && y >= r )
	{
		if (c < mex[root].mn)
		{
			mex[root].mx = mex[root].mn = c;
			mex[root].sz = c;
			int k = max(cur, l);
			mex[root].sum = (LL)(r-k+1) * c;		
			return;
		}
		if (c > mex[root].mx)
		{
			if (l >= cur) return;
		}		
	}
	int mid;
	pushDOWN(l,r,m,root);
	if (x <= m && m >= cur)
	{
		change(c,x,y,lson);
	}
	if (y > m && r >= cur)
	{
		change(c,x,y,rson);
	}
	pushUP(l,r,m,root);
}

int main() 
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	while (scanf("%d", &n)!=EOF && n)
	{
		for (int i = 0; i< n; ++i)
		{
			scanf("%d", &num[i]);
			if (num[i] > n) num[i] = n+1;
		}
		int c = 0;
		memset(next, 0, sizeof next);
		for (int i = 0; i< n; ++i)
		{
			next[num[i]] = 1;
			while (next[c]) c++;
			data[i] = c;
		}
		memset(pp, -1, sizeof pp);
		for (int i = n-1; i>= 0; --i)
		{
			next[i] = pp[num[i]];
			pp[num[i]] = i;
		}
		cur = 0;
		build(0,n-1, 1);
		LL res = mex[1].sum;
		for (int i = 0; i < n-1; ++i)
		{
			cur = i+1;
			if (num[i] != num[i+1])
			{				
				if (next[i] == -1)
					change(num[i], i+1, n-1, 0, n-1, 1);
				else
					change(num[i], i+1, next[i]-1, 0, n-1, 1);				
			}
			else
			{
				change(INF,i+1,i+1,0,n-1,1);
			}
			res += mex[1].sum;
		}
		printf("%I64d\n", res);		
	}
    return 0;
}


hdu 3642 Get The Treasury

利用线段树求区间重叠,原理上和 hdu 1255 差不多。。。
加入点优化,Node 中的 one ,two, more 表示 大于等于 1,2,3 次,这样在段汇总的时候就可以省去一些步骤
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
/* 
	http://acm.hdu.edu.cn/showproblem.php?pid=3642
*/
const int MAXN = 3000;
#define LL __int64  
#define ll (root<<1)  
#define rr (ll|1)  
#define lson l,mm,ll  
#define rson mm,r,rr  
#define mid mm=(l+r)>>1  
struct mFace
{
	int y;
	int x1, x2, z1, z2;
	int sz;
	mFace(){}
	mFace(int _y, int _x1, int _x2, int _z1, int _z2, int _sz)
	:y(_y), x1(_x1), x2(_x2), z1(_z1), z2(_z2), sz(_sz)
	{}
	bool operator < (const mFace & a) const
	{
		return y < a.y;
	}
}mf[MAXN], tp[MAXN];
struct Node
{
	int one, two, more;
	int c, x1, x2, y;	// cnt; range x1, x2; y
	int l, r;	// index
	int len;
	void init()
	{
		one = two = more = 0;
		c = 0; len = x2-x1;
	}
}nd[MAXN*3];
int xx[MAXN], zz[MAXN];
void build (int l, int r, int root)
{
	nd[root].x1 = xx[l]; nd[root].x2 = xx[r];
	nd[root].l = l, nd[root].r = r;
	nd[root].init();
	if (l+1 == r) return;
	int mid;
	build(lson);
	build(rson);
}
void pushUP(int root)
{
	int l = nd[root].l, r = nd[root].r;
	if (nd[root].c == 0)
	{
		if (l+1 == r)
		{
			nd[root].one = nd[root].two = nd[root].more = 0;
		}
		else
		{
			nd[root].one = nd[ll].one + nd[rr].one;
			nd[root].two = nd[ll].two + nd[rr].two;
			nd[root].more = nd[ll].more + nd[rr].more;
		}
	}
	else if (nd[root].c == 1)
	{
		nd[root].one = nd[root].len;
		if (l + 1 == r)
		{			
			nd[root].two = nd[root].more = 0;
		}
		else
		{
			nd[root].two = nd[ll].one + nd[rr].one;
			nd[root].more = nd[ll].two + nd[rr].two;
		}
	}
	else if (nd[root].c == 2)
	{
		nd[root].one = nd[root].two = nd[root].len;
		if (l+1 == r)
		{
			nd[root].more = 0;
		}
		else
		{
			nd[root].more = nd[ll].one + nd[rr].one;
		}
	}
	else
	{		
		nd[root].one = nd[root].two = nd[root].more = nd[root].len;
	}
}
void change(int root, int x1, int x2, int c)
{
	if (x1 <= nd[root].x1 && x2 >= nd[root].x2)
	{
		nd[root].c += c;
		if (nd[root].c == 2)
		{
			printf("");
		}
		pushUP(root);
		return;
	}
	if (x1 < nd[ll].x2)	change(ll, x1, x2, c);
	if (x2 > nd[rr].x1) change(rr, x1, x2, c);
	pushUP(root);
}
int main() 
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int t;
	scanf("%d", &t);
	for (int _ = 1; _ <= t; ++_)
	{
		printf("Case %d: ", _);
		int n, k = 0;
		scanf("%d", &n);
		for (int i = 0; i< n; ++i)
		{
			int x1, y1, z1, x2, y2, z2;
			scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2);
			mf[k] = mFace(y1, x1, x2, z1, z2, 1);
			xx[k] = x1; zz[k++] = z1;
			mf[k] = mFace(y2, x1, x2, z1, z2, -1);
			xx[k] = x2; zz[k++] = z2;
		}
		sort(mf, mf+k);
		sort(xx, xx+k);
		sort(zz, zz+k);
		int k1 = unique(xx, xx+k) - xx;
		int k2 = unique(zz, zz+k) - zz;
		build(0,k1-1,1);
		LL res = 0;
		int m;
		for (int i = 0; i < k2-1; ++i)
		{
			m = 0;
			for (int j = 0; j< k; ++j)
			{
				if (mf[j].z1 <= zz[i] && mf[j].z2 >= zz[i+1])
				{
					tp[m++] = mf[j];
				}
			}
			LL sum = 0;
			for (int j = 0; j< m; ++j)
			{
				if (j != 0)
					sum += (LL)nd[1].more * (LL)(tp[j].y - tp[j-1].y);
				change(1, tp[j].x1, tp[j].x2, tp[j].sz);
			}
			res += sum * (zz[i+1] - zz[i]);
		}
		printf("%I64d\n", res);
	}	
    return 0;
}


hdu 4419 Colourful Rectangle

如果搞懂了上一题,这题也差不多了,稍微加点变化
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
// http://acm.hdu.edu.cn/showproblem.php?pid=4419
const int MAXN = 25000;
#define LL __int64  
#define ll (root<<1)  
#define rr (ll|1)  
#define lson l,mm,ll  
#define rson mm,r,rr  
#define mid mm=(l+r)>>1  
struct mFace
{
	int y, x1, x2;
	int c, f;
	bool operator < (const mFace & a) const
	{
		return y < a.y;
	}
	void getIn(int yy, int xx1, int xx2, int cc, int ff)
	{
		y = yy; x1 = xx1; x2 = xx2; c = cc; f = ff;
	}
}mf[MAXN];
const int MONE = 10*4;
const int MC = 5*4;
struct Node
{
	int one[10];
	int c[5], d;
	int x1, x2;	
	int l, r;
	int len;
	void init()
	{
		memset(one, 0, MONE);
		memset(c, 0, MC);
		d = 0;
		len = x2-x1;
	}
	void cal()
	{
		d = 0;
		for (int i = 0; i< 3; ++i)
		{
			if (c[i]) d |= 1<<i;
		}
	}
}nd[MAXN*3];
int xx[MAXN];
void build (int l, int r, int root)
{
	nd[root].x1 = xx[l]; nd[root].x2 = xx[r];
	nd[root].l = l, nd[root].r = r;
	nd[root].init();
	if (l+1 == r) return;
	int mid;
	build(lson);
	build(rson);
}
void pushUP(int root)
{
	int l = nd[root].l, r = nd[root].r;
	int d = nd[root].d;
	if (d == 0)
	{
		if (l+1 == r)
		{
			memset(nd[root].one, 0, MONE);			
		}
		else
		{
			for (int i = 1; i<8; ++i)
			{
				nd[root].one[i] = nd[ll].one[i] + nd[rr].one[i];
			}
		}
	}
	else
	{
		if (l+1 == r)
		{
			for (int i = 1; i< 8; ++i)
			{
				if ((i&d) == i)
				{
					nd[root].one[i] = nd[root].len;
				}
				else
				{
					nd[root].one[i] = 0;
				}
			}
		}
		else
		{
			for (int i = 1; i< 8; ++i)
			{
				if ((i&d) == i)
				{
					nd[root].one[i] = nd[root].len;
				}
				else
				{
					int a = i-(i&d);
					nd[root].one[i] = nd[ll].one[a] + nd[rr].one[a];
				}
			}
		}
	}
}
void change(int root, int x1, int x2, int c, int ff)
{
	if (x1 <= nd[root].x1 && x2 >= nd[root].x2)
	{
		nd[root].c[c] += ff;
		nd[root].cal();
		pushUP(root);
		return;
	}
	if (x1 < nd[ll].x2)	change(ll, x1, x2, c, ff);
	if (x2 > nd[rr].x1) change(rr, x1, x2, c, ff);
	pushUP(root);
}
char str[5];
int mot[10] = {1,2,4,3,5,6,7};
int main() 
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int t;
	scanf("%d", &t);
	for (int _ = 1; _ <= t; ++_)
	{
		printf("Case %d:\n", _);
		int n, k = 0;
		scanf("%d", &n);
		for (int i = 0; i< n; ++i)
		{			
			int x1, x2, y1, y2, c, f;
			scanf("%s%d%d%d%d", str, &x1, &y1, &x2, &y2);
			switch (str[0])
			{
				case 'R': c = 0; break;
				case 'G': c = 1; break;
				case 'B': c = 2; break;
			}
			mf[k].getIn(y1,x1,x2,c,1);
			xx[k++] = x1;
			mf[k].getIn(y2,x1,x2,c,-1);
			xx[k++] = x2;
		}
		sort(mf, mf+k);
		sort(xx,xx+k);
		int k1 = unique(xx, xx+k) - xx;
		build(0,k1-1,1);
		LL res[10], nima; 
		LL tp[10];
		int ap[10];
		memset(res, 0, sizeof res);
		for (int i = 0; i< k; ++i)
		{
			if (i != 0)
			{
				memcpy(ap, nd[1].one, MONE);
				tp[7] = ap[7]; tp[6] = ap[6]-ap[7]; tp[5]=ap[5]-ap[7];
				tp[3]=ap[3]-ap[7];
				LL cao = tp[7]+tp[6]+tp[5]+tp[3];
				tp[4]=ap[4]-tp[5]-tp[6]-tp[7]; 
				tp[2]=ap[2]-tp[3]-tp[6]-tp[7];  
				tp[1]=ap[1]-tp[3]-tp[5]-tp[7]; 
				nima = (mf[i].y - mf[i-1].y);
				for (int j = 1; j< 8; ++j)
					res[j] += tp[j]*nima;
			}
			change(1, mf[i].x1, mf[i].x2, mf[i].c, mf[i].f);
		}
		for (int i = 0; i< 7; ++i)
		{
			printf("%I64d\n", res[mot[i]]);
		}
	}	
    return 0;
}


hdu 4288 Coder

算是线段树里一个比较巧妙的应用吧
LL num[5]; 表示该段中偏移i个位置后,每隔5个数相加和
int cnt; 表示段中数的个数
结果显而易见就是 总段偏移2个位置后(从第三个数起)的结果
#include <cstdio>
#include <iostream>
#include <cmath>
#include <set>
#include <algorithm>
using namespace std;
// http://acm.hdu.edu.cn/showproblem.php?pid=4288
const int MAXN = 100005;
#define LL __int64  
#define ll (root<<1)  
#define rr (ll|1)  
#define lson l,mm,ll  
#define rson mm+1,r,rr  
#define mid mm=(l+r)>>1  
const int N = 5*sizeof(LL);
struct Node
{
	LL num[5];
	int cnt;
	int x1, x2;	
	void init() {memset(num, 0, N); cnt = 0;}
}nd[MAXN*3];
int xx[MAXN], q[MAXN], s[MAXN];
void build (int l, int r, int root)
{
	nd[root].x1 = xx[l]; nd[root].x2 = xx[r];
	nd[root].init();
	if (l == r) return;
	int mid;
	build(lson);
	build(rson);
}
void pushUP(int root)
{
	int l = ll, r = rr, c1, c2;
	nd[root].cnt = (c1=nd[l].cnt) + nd[r].cnt;
	for (int i = 0; i< 5; ++i)
	{
		if (c1 < i)
		{
			nd[root].num[i] = nd[l].num[i] + nd[r].num[i-c1];
		}
		else if (c1 == i)
		{
			nd[root].num[i] = nd[r].num[0];
		}
		else
		{
			c2 = (c1-i)%5;
			if (c2 != 0) c2 = 5-c2;
			nd[root].num[i] = nd[l].num[i] + nd[r].num[c2];
		}		
	}
}
void change(int root, int x, int c)
{
	if (nd[root].x2 == nd[root].x1)
	{
		if (c == 1)
		{
			nd[root].cnt = 1;
			nd[root].num[0] = x;
		}
		else
		{
			nd[root].init();
		}
		return;
	}
	if (x <= nd[ll].x2) change(ll,x,c);
	else change(rr,x,c);
	pushUP(root);
}
char str[5];
set<int> mset;
set<int>::iterator it;
int main() 
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int n;
	while (scanf("%d", &n) != EOF)
	{
		mset.clear();
		for (int i = 0; i< n; ++i)
		{			
			scanf("%s", str);
			if (strcmp(str, "add") == 0)
			{
				scanf("%d", s+i);
				q[i] = 1;
				mset.insert(s[i]);
			}
			else if (strcmp(str, "del") == 0)
			{
				scanf("%d", s+i);
				q[i] = -1;
			}
			else
			{
				q[i] = 3;
			}
		}
		int k = 0;
		for (it = mset.begin(); it != mset.end(); ++it)
		{
			xx[k++] = *it;
		}
		build(0,k-1,1);
		for (int i = 0; i< n; ++i)
		{
			if (q[i] != 3) 
				change(1,s[i],q[i]);
			else 
				printf("%I64d\n", nd[1].num[2]);
		}
	}	
    return 0;
}


hdu 4267 A Simple Problem with Integers

这算是比较灵活的线段树的应用
一开始卡在如何解决延迟更新的问题上,借鉴了别人的思路,把求结果的那部分从低开始递归,这样就不需要延迟更新
算是个教训吧
#include <cstdio>
#include <iostream>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
// http://acm.hdu.edu.cn/showproblem.php?pid=4267
using namespace std;
const int MAXN = 50005;
const int NN = 11*sizeof(int);
#define ll (root<<1)
#define rr (ll | 1)
#define lson l,m,ll
#define rson m+1,r,rr
#define mid m=(l+r)>>1
struct node
{
	int l, r;
	int sz[11];
}data[MAXN*3];
int num[MAXN], mmp[MAXN];
void build(int l, int r, int root)
{
	data[root].l = l; data[root].r = r;
	memset(data[root].sz, 0, NN);
	if (l == r) 
	{
		mmp[l] = root;
		return;
	}
	int mid;
	build(lson);
	build(rson);
}
void change(int c, int k, int x, int y, int l, int r, int root)
{
	if (x > y) return;
	if (x == l && y == r)
	{
		data[root].sz[k] += c;
		return;
	}
	int mid;
	if (y <= m) change(c,k,x,y,lson);
	else if (x > m) change(c,k,x,y,rson);
	else
	{
		change(c,k,x,m,lson);
		int a = (m-x)/k;
		change(c,k,x+(a+1)*k, y,rson);
	}
}
int getSum(int a, int root)
{
	int l = data[root].l;
	int res = 0;
	for (int i = 1; i< 11; ++i)
	{
		if ((a-l)%i == 0) res += data[root].sz[i];
	}
	if (root != 1) res += getSum(a,root>>1);
	return res;
}

int main() 
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int n;
	while (scanf("%d", &n) != EOF)
	{
		for (int i = 1; i<= n; ++i) scanf("%d", num+i);
		build(1,n,1);
		int m;
		scanf("%d", &m);
		while (m--)
		{
			int t,a,b,k,c;
			scanf("%d", &t);
			if (t == 1)
			{
				scanf("%d%d%d%d", &a, &b, &k, &c);
				change(c,k,a,b,1,n,1);
			}
			else
			{
				scanf("%d", &a);
				printf("%d\n", num[a]+getSum(a,mmp[a]));
			}
		}
	}
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

线段树合集

定义: 线段树是建立在线段的基础上,每个结点都代表了一条线段[a , b]。长度为1的线段称为元线段。非元线段都有两个子结点,左结点代表的线段为[a , (a + b ) / 2],右结点代表的线段...

线段树 lazy tag 小合集

(这里的基础和进阶纯粹是根据PO主水平说的…大家意思意思看看就好Orz)基础 poj 3468 hiho 1078 poj 2777 hdu 4902 进阶 hdu 3911 hdu 3397 未完待...

线段树模板合集--单点替换,区间替换,区间增加3种情况

单点替换,单点增加,区间求最值,区间求和#include #include #include using namespace std; #define lson l , m , rt << 1 ...

SPOJ 1716 GSS3 Can you answer these queries III 线段树区间合并

传送门:SPOJ 1716 题意 求动态区间最大子段和 题解 线段树区间合并维护区间和, 左右连续最大字段和, 最大字段和 AC code:#include #include #include...
  • ADjky
  • ADjky
  • 2017-01-17 17:21
  • 107

POJ 2528(summer III X) 区间离散化,线段树区间更新

一直在用树状数组解题,线段树都有点忘了。。。。 参考了别人的代码后终于明白了离散化的道理和步骤,一下为参考网址:点击打开链接 #include #include #include using na...

SPOJ/GSS3:Can you answer these queries III(线段树)

http://www.spoj.pl/problems/GSS3/ 题意:给出一个数列,求某个区间内的最大子序列和,并进行对某些点的更新。GSS1是个不更新只查询的简化版题目,差别不大。 跟hdu...

【SPOJ】1716 Can you answer these queries III 线段树

传送门:【SPOJ】1716 Can you answer these queries III

spoj 1716. Can you answer these queries III(线段树)

题目链接:http://www.spoj.com/problems/GSS3/   题意:给出n个数,有两个操作,一个是查询区间最大子段和,另一个是修改某一个数。   思路:其实这题挺简单,依...

HDU 5266 pog loves szh III (线段树+在线LCA转RMQ)

题目地址:HDU 5266 这题用转RMQ求LCA的方法来做的非常简单,只需要找到l-r区间内的dfs序最大的和最小的就可以,那么用线段树或者RMQ维护一下区间最值就可以了。然后就是找dfs序最大的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)