PKU A Simple Problem with Integers 3468

April 27th, 2009 No comments

题目地址
对于Q操作,求出区间的总和,对于C操作,将区间里的所有数都加上同一个数
考虑结点存放两个信息,一个是该结点区间内的和s,一个是该区间所有数的增量d,对于一个C操作,如果区间刚好等于某结点的区间,则直接将增量加上去,否则,递归到左右子结点,并更新父结点的s值。这样,对于插入与查询都能达到O(logn)的复杂度.
Memory: 6760K
Time: 1579MS

#include <iostream>
using namespace std;
#define ll long long
const int MAXN = 100001;
struct {
	int l, r;
	ll s, d;
} nod[MAXN*3];
int a[MAXN];
void creat(int t, int l, int r) {
	if(l == r) {
		nod[t].l = nod[t].r = l, nod[t].s = a[l], nod[t].d = 0;
		return;
	}
	int m = (l+r) / 2;
	nod[t].l = l, nod[t].r = r, nod[t].d = 0;
	creat(t*2, l, m), creat(t*2+1, m+1, r);
	nod[t].s = nod[t*2].s + nod[t*2+1].s;
}
void inc(int t, int l, int r, int c) {
	if(l == nod[t].l && r == nod[t].r) {nod[t].d += c; return;}
	if(r <= nod[t*2].r) inc(t*2, l, r, c);
	else if(l >= nod[t*2+1].l) inc(t*2+1, l, r, c);
	else inc(t*2, l, nod[t*2].r, c), inc(t*2+1, nod[t*2+1].l, r, c);
	nod[t].s = nod[t*2].s + nod[t*2].d * (nod[t*2].r-nod[t*2].l+1) + nod[t*2+1].s + nod[t*2+1].d * (nod[t*2+1].r-nod[t*2+1].l+1);
}
ll query(int t, int l, int r) {
	if(nod[t].l == l && nod[t].r == r) return nod[t].s + nod[t].d * (r-l+1);
	ll sum;
	if(r <= nod[t*2].r) sum = query(t*2, l, r);
	else if(l >= nod[t*2+1].l) sum = query(t*2+1, l, r);
	else sum = query(t*2, l, nod[t*2].r) + query(t*2+1, nod[t*2+1].l, r);
	return sum + nod[t].d * (r-l+1);
}
int main() {
	int i, n, q, x1, x2, c;
	char s[2];
	while(scanf("%d%d", &n, &q) != EOF) {
		for(i = 1; i <= n; i++) scanf("%d", &a[i]);
		creat(1, 1, n);
		while(q--) {
			scanf("%s%d%d", s, &x1, &x2);
			if(s[0] == 'C') {scanf("%d", &c); inc(1, x1, x2, c);}
			else printf("%lld\n", query(1, x1, x2));
		}
	}
	return 0;
}
Categories: ACM Tags: ,

PKU Frequent values 3368

April 27th, 2009 2 comments

题目地址
给定一组非降序的元素,求区间重复最多次的元素的重复次数。
貌似现在只会用线段树写,先放出线段树的方法
在每个结点存放三个信息,lf代表该结点所表示的区间最左边连续的相同元素的次数,rf代表右边连续的相同元素的次数,m代表该区间中重复最多次的元素的重复次数。
lf的取值,当为以下情况时
segment tree 1
很明显lf等于左子结点的lf的值
当为以下情况时
segment tree 2
很明显lf等于左子结点的lf的值加上右子结点的lf的值
容易知道rf与lf类似
对于m的求法,如果
segment tree 3
则m=MAX{左结点的m,右结点的m}
如果
segment tree 4
则m=MAX{左结点的m,右结点的m,左结点的rf+右结点的lf}
而在查询的过程中,需要注意一点的是,如果区间分属于某个结点的左右子结点中,且左右子结点的连接处的值是相等的,那么我们还要考虑这两部分相加的值是否会为最大,即MAX{左结点的m,右结点的m}后,还要判断MIN{左结点的rf,l-左点的右区间+1}+MIN{右结点的lf,r-右结点的左区间+1}是否会更大,为什么要分别取最小值再相加呢,因为左结点的rf只是单纯考虑其右边连续的个数,如果其个数超过给定区间的左边界,当然不能全都计算在内,所以有MIN{左结点的rf,l-左点的右区间+1}。
Memory: 5736K
Time: 750MS

#include <iostream>
using namespace std;
const int MAXN = 100001;
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
int a[MAXN], n;
struct {
	int l, r, lf, rf, m;
} nod[MAXN*3];
void init(int t, int l, int r) {
	if(l == r) {
		nod[t].l = nod[t].r = l;
		nod[t].lf = nod[t].rf = nod[t].m = 1;
		return;
	}
	int m = (l + r) / 2, tmp, sum;
	nod[t].l = l, nod[t].r = r;
	init(t*2, l, m), init(t*2+1, m+1, r);
	nod[t].lf = nod[t*2].lf, nod[t].rf = nod[t*2+1].rf;
	tmp = Max(nod[t*2].m, nod[t*2+1].m);
	if(a[nod[t*2].r] == a[nod[t*2+1].l]) {
		sum = nod[t*2].rf + nod[t*2+1].lf, tmp = Max(tmp, sum);
		if(a[nod[t].l] == a[nod[t*2].r]) nod[t].lf = sum;
		if(a[nod[t].r] == a[nod[t*2+1].l]) nod[t].rf = sum;
	}
	nod[t].m = tmp;
}
int query(int t, int l, int r) {
	if(nod[t].l == l && nod[t].r == r) return nod[t].m;
	if(r <= nod[t*2].r) return query(t*2, l, r);
	if(l  >= nod[t*2+1].l) return query(t*2+1, l, r);
	int q1 = query(t*2, l, nod[t*2].r), q2 = query(t*2+1, nod[t*2+1].l, r), tmp = Max(q1, q2);
	if(a[nod[t*2].r] == a[nod[t*2+1].l]) tmp = Max(tmp, Min(nod[t*2].r-l+1, nod[t*2].rf)+Min(r-nod[t*2+1].l+1, nod[t*2+1].lf));
	return tmp;
}
int main() {
	int q, i, x1, x2;
	while(scanf("%d", &n), n) {
		scanf("%d", &q);
		for(i = 1; i <= n; i++) scanf("%d", &a[i]);
		init(1, 1, n);
		while(q--) {
			scanf("%d%d", &x1, &x2);
			printf("%d\n", query(1, x1, x2));
		}
	}
	return 0;
}
Categories: ACM Tags: ,

专题之线段树学习(持续更新)

April 27th, 2009 2 comments

HDU
1255 覆盖的面积 http://acm.hdu.edu.cn/showproblem.php?pid=1255
|—–Accepted 492K 343MS
|———- http://hi.baidu.com/phoenixwright/blog/item/47413c440ae34737879473dc.html

http://acm.hdu.edu.cn/showproblem.php?pid=1394
1542 Atlantis http://acm.hdu.edu.cn/showproblem.php?pid=1542
|—–Accepted 248K 0MS
|———- http://hi.baidu.com/phoenixwright/blog/item/f0b955eca95a904778f055ee.html

1698 Just a Hook http://acm.hdu.edu.cn/showproblem.php?pid=1698
|—–Accepted 3284K 406MS
|———- http://hi.baidu.com/phoenixwright/blog/item/b80dd6f1fb7a23cb7931aafd.html

1754 I Hate It http://acm.hdu.edu.cn/showproblem.php?pid=1754
|—–Accepted 7148K 468MS
|———- http://hi.baidu.com/phoenixwright/blog/item/6a4214a0176ffe83471064af.html

http://acm.hdu.edu.cn/showproblem.php?pid=1779
1828 Picture http://acm.hdu.edu.cn/showproblem.php?pid=1828
|—–Accepted 492K 15MS
|———- http://hi.baidu.com/phoenixwright/blog/item/72a8bbcf6ce07531b600c8e4.html

ZJU
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=610
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2706
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2859
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2451
PKU
2777 Count Colors http://acm.pku.edu.cn/JudgeOnline/problem?id=2777
|—–Accepted 3284K 250MS
|———- http://hi.baidu.com/phoenixwright/blog/item/1026ad4e82516a3eafc3ab8b.html

2892 Tunnel Warfare http://acm.pku.edu.cn/JudgeOnline/problem?id=2892
|—–Accepted 1912K 204MS
|———- http://hi.baidu.com/phoenixwright/blog/item/ae8c98d2b4a52c083af3cf8d.html

3468 A Simple Problem with Integers http://acm.pku.edu.cn/JudgeOnline/problem?id=3468
|—–Accepted 6760K 1579MS
|———- http://hi.baidu.com/phoenixwright/blog/item/b4f1a125bc51523bc9955927.html

3368 Frequent values http://acm.pku.edu.cn/JudgeOnline/problem?id=3368
|—–Accepted 5736K 750MS
|———- http://hi.baidu.com/phoenixwright/blog/item/7559331758e22459f3de3201.html

2528 Mayor’s posters http://acm.pku.edu.cn/JudgeOnline/problem?id=2528
3277 City Horizon http://acm.pku.edu.cn/JudgeOnline/problem?id=3277
|—–Accepted 5740K 485MS
|———- http://hi.baidu.com/phoenixwright/blog/item/b2617355f2083250d10906f7.html

1389 Area of Simple Polygons http://acm.pku.edu.cn/JudgeOnline/problem?id=1389
http://acm.pku.edu.cn/JudgeOnline/problem?id=3225
http://acm.pku.edu.cn/JudgeOnline/problem?id=2482
http://acm.pku.edu.cn/JudgeOnline/problem?id=2828
http://acm.pku.edu.cn/JudgeOnline/problem?id=2464
http://acm.pku.edu.cn/JudgeOnline/problem?id=2985
http://acm.pku.edu.cn/JudgeOnline/problem?id=3145
http://acm.pku.edu.cn/JudgeOnline/problem?id=2274
http://acm.pku.edu.cn/JudgeOnline/problem?id=2886
http://acm.pku.edu.cn/JudgeOnline/problem?id=2760
FZU
1608 Huge Mission http://acm.fzu.edu.cn/problem.php?pid=1608
|—–Accepted 2370K 1.2S
|———- http://hi.baidu.com/phoenixwright/blog/item/1f80d31f076f91fc1bd576a5.html

Categories: ACM, Algorithm Tags: , ,

FZU 最大树高 1712

April 26th, 2009 No comments

题目地址
给定一棵树,求当该树以某点为根时的最大树高,并输出满足最大树高的最小节点
根据许多大牛的方法,一次以任意顶点进行搜索找到最深的顶点,再以该顶点搜索一次即可,不明白为啥这样-_-
本来想直接开个数组,发现那样实在太大了,又懒得写链表,还是用vector方便些。。。
发现速度好慢。。囧。。

#include <iostream>
#include <vector>
using namespace std;
const int N = 100000;
vector<int>a[N+1];
int n, height[N+1];
void dfs(int l) {
	for(int i = 0; i < a[l].size(); i++)
		if(height[a[l][i]] == -1) {
			height[a[l][i]] = height[l] + 1;
			dfs(a[l][i]);
		}
}
int solve(int l) {
	int i, j;
	memset(height, 0xff, sizeof(height));
	height[l] = 1, dfs(l);
	for(i = 2, j = 1; i <= n; i++) if(height[j] < height[i]) j = i;
	return j;
}
int main() {
	int i, j, x1, x2;
	while(scanf("%d", &n) != EOF) {
		for(i = 1; i <= n; i++) a[i].clear();
		for(i = 1; i < n; i++) {
			scanf("%d%d", &x1, &x2);
			a[x1].push_back(x2);
			a[x2].push_back(x1);
		}
		i = solve(1), j = solve(i);
		printf("%d %d\n", i < j ? i : j, height[j]);
	}
	return 0;
}
Categories: ACM, Algorithm Tags: ,

HDU 搬寝室 1421

April 26th, 2009 No comments

题目地址

题目大意是,给定n个数,每次选择2个数(取出后不放回),求出两数之差的平方,累加,选k对(k<=n/2),问最终累加之和最小为多少

先对n个数排序,因为结果要求最小,那么每次择时,只能选择相邻的两个数,只有这样,最终的差才可能最小,构造dp[i][j],代表从1到n个物品中选择k对,那么状态转移方程为

dp[i][j]=Min{dp[i-2][j-1]+a[i-1],dp[i-1][j]}

其中a[i-1]存放的是第i与第i-1个数的差的平方。

#include <iostream>
#include <algorithm>
using namespace std;
#define Min(a,b) ((a) < (b) ? (a) : (b))
#define INF 2100000000
int dp[2001][1001];
int main() {
    int i, j, n, k, a[2001];
    while(scanf("%d%d", &n, &k) != EOF) {
        for(i = 1; i <= n; i++) scanf("%d", &a[i]);
        sort(a+1, a+1+n);
        for(i = 1; i < n; i++) a[i] = (a[i]-a[i+1]) * (a[i]-a[i+1]);
        for(i = 0; i <= n; i++)
            for(j = 1; j <= k; j++)
                dp[i][j] = INF;
        for(i = 0; i <= n; i++) dp[i][0] = 0;
        for(i = 2; i <= n; i++)
            for(j = 1; j * 2 <= i; j++)
                dp[i][j] = Min(dp[i-2][j-1]+a[i-1], dp[i-1][j]);
        printf("%d\n", dp[n][k]);
    }
    return 0;
}
Categories: ACM Tags: ,

PKU Cow Contest 3660

April 26th, 2009 No comments

题目地址
题目大意是给出一系列奶牛的比赛列表,如果奶牛A战胜奶牛B,那么奶牛A的排名就在奶牛B的前面,给出一系列A beat B的列表,计算出有多少只奶牛能够确认它们的排名位置

假设有n只奶牛,那么某只牛的排名能确定的条件是该牛打败的牛数加打败该牛的数之和等于n-1,构造出图求每个顶点的入度与出度即可

#include <iostream>
using namespace std;
int main() {
	int n, m, i, j, k, x1, x2, d, ans;
	bool a[101][101];
	while(cin >> n >> m) {
		memset(a, 0, sizeof(a));
		while(m--) cin >> x1 >> x2, a[x1][x2] = true;
		for(k = 1; k <= n; k++)
			for(i = 1; i <= n; i++)
				for(j = 1; j <= n; j++)
					a[i][j] = a[i][j] || a[i][k] && a[k][j];
		for(i = 1, ans = 0; i <= n; i++) {
			for(j = 1, d = 0; j <= n; j++) {
				if(a[i][j]) d++;
				if(a[j][i]) d++;
			}
			if(d == n-1) ans++;
		}
		cout << ans << endl;
	}
	return 0;
}
Categories: ACM Tags: ,

欧拉函数

April 26th, 2009 1 comment

返回与数n互质的数的个数

int eular(int n) {
       int ret = 1, i;
       for (i = 2; i * i <= n; i++)
           if (!(n % i)) {
                  n /= i;
                  ret *= i - 1;
                  while (!(n % i)) n /= i,  ret *= i;
            }
        if(n > 1) ret *= n - 1;
       return ret;
}
Categories: Algorithm Tags: ,

大数模板

April 26th, 2009 No comments
#include <iostream>
using namespace std;
#include <math.h>
#define SWAP(a, b) a ^= b ^= a ^= b
const int  M = 10000;							//几进制
const int W = 4;		//对应M进制时每个数组存放几位 (int)(log10(M-1.0))+1;
#if M > 10000
#define Elem long long
#else
#define Elem int
#endif
const int N = 1000;			//要计算的数最大有几位
struct BigNum {
	Elem a[N/W+1];
	int l, len;
	BigNum() {
		l = len = 1;
		memset(a, 0, sizeof(a));
	}
	BigNum(char *p) {
		memset(a, 0, sizeof(a));
		split(p);
	}
	void split(char *p) {
		int i, j, k, s;
		len = strlen(p);
		l = len / W;
		if((s = len % W)) l++;
		else s = W;
		a[0] = 0;
		for(i = 0; i < s; i++) a[0] = a[0] * 10 + p[i] - '0';
		for(i = s, j = 1; j < l; j++) {
			a[j] = 0;
			for(k = 0; k < W; k++, i++)
				a[j] = a[j] * 10 + p[i] - '0';
		}
	}
	void print() {
		int i;
		printf("%d", a[0]);
		for(i = 1; i < l; i++) printf("%04d", a[i]);
		putchar('\n');
	}
	BigNum operator +(BigNum b) {
		BigNum c;
		int i, j, k, f = 0;
		for(i = l-1, j = b.l-1, k = 0; i >= 0 || j >= 0; i--, j--, k++) {
			c.a[k] = f;
			if(i >= 0) c.a[k] += a[i];
			if(j >= 0) c.a[k] += b.a[j];
			if(c.a[k] >= M) f = c.a[k] / M, c.a[k] %= M;
			else f = 0;
		}
		if(f == 1) c.a[k++] = 1;
		c.l = k;
		if(c.l == 1 && c.a[0] < 10) c.len = 1;
		else c.len = (c.l -  1)* W + (int)(log10((double)c.a[0]))+1;
		for(i = 0, j = k - 1; i < j; i++, j--)
			SWAP(c.a[i], c.a[j]);
		return c;
	}
	BigNum operator -(BigNum b) {
		BigNum c;
		int la = l-1, lb = b.l-1, i, j, m = 0, k;
		for(i = la, j = lb, k = 0; i >= 0 && j >= 0; i--, j--, k++) {
			c.a[k] = a[i] + M - b.a[j] - m;
			if(c.a[k] >= M) c.a[k] -= M, m = 0;
			else m = 1;
		}
		while(i >= 0) {
			c.a[k] = a[i] + M - m;
			if(c.a[k] >= M) c.a[k] -= M, m = 0;
			else m = 1;
			k++, i--;
		}
		k--;
		while(c.a[k] == 0 && k > 0) k--;
		c.l = k + 1;
		for(i = 0, j = c.l-1; i < j; i++, j--) SWAP(c.a[i], c.a[j]);
		if(c.l == 1 && c.a[0] < 10) c.len = 1;
		else c.len = (c.l -  1)* W + (int)(log10((double)c.a[0]))+1;
		return c;
	}
	BigNum operator *(int data) {
		BigNum t;
		int f[N/W+1] = {0};
		int i, j = 2, fl = 0, n;
		for(i = 0; i < l; i++, j++) {
			f[j] = a[i] * data;
		}
		n = j;
		for(j--; j >= 0; j--) {
			f[j] += fl;
			fl = f[j] / M;
			f[j] %= M;
		}
		i = 0;
		while(f[i] == 0 && i < n) i++;
		if(i == n) i--;
		for(j = 0; i < n; j++, i++) t.a[j] = f[i];
		t.l = j;
		if(t.l == 1 && t.a[0] < 10) t.len = 1;
		else t.len = (t.l -  1)* W + (int)(log10((double)t.a[0]))+1;
		return t;
	}
	BigNum operator *(BigNum b) {
		BigNum c;
		int i, j;
		Elem *s, r;
		int la = l, lb = b.l, p;
		s = (Elem*)malloc(sizeof(Elem) * (l+b.l));
		memset(s, 0, sizeof(Elem) * (la+lb));
		for(i = lb - 1; i >= 0; i--) {
			for(j = la - 1, r = 0; p = la + lb - i - j - 2, j >= 0; j--) {
				r += (Elem)a[j] * b.a[i];
				s[p] += r % M;
				r /= M;
				if(s[p] >= M) s[p] -= M, r++;
			}
			if(r) s[p] = r;
		}
		for(i = la + lb - 1, j = 0; !s[i] && i > 0; i--);
		while(i >= 0) c.a[j++] = s[i--];
		c.l = j;
		if(c.l == 1 && c.a[0] < 10) c.len = 1;
		else c.len = (c.l -  1)* W + (int)(log10((double)c.a[0]))+1;
		free(s);
		return c;
	}	
	BigNum operator /(int b) {
		int i, t = 0, j, f = 0;
		BigNum c;
		for(i = 0, j = 0; i < l; i++) {
			t = t * M + a[i];
			if(!f && t / b) {c.a[j++] = t / b; f = 1;}
			else if(f) c.a[j++] = t / b;
			t %= b;
		}
		c.l = j;
		if(c.l == 1 && c.a[0] < 10) c.len = 1;
		else c.len = (c.l -  1)* W + (int)(log10((double)c.a[0]))+1;
		return c;
	}
};
Categories: ACM Tags: ,

在这里安家了。。。。

April 26th, 2009 3 comments

在现在开始,要在这里好好写博客了哈!

Categories: My Life Tags: ,