zoukankan      html  css  js  c++  java
  • codeforces 几道题目

    BZOJ挂了....明天就要出发去GDKOI了....不能弃疗. 于是在cf水了几道题, 写写详(jian)细(dan)题解, 攒攒RP, 希望GDKOI能好好发挥....... 

    620E. New Year Tree

    题目大意:

    N个结点的树, 结点1为根, 要支持2种操作(M个操作):

    1.将以v为根的子树所有节点的颜色为c

    2.询问以v为根的子树中不同颜色个数

    N,M<=4*10^5, 1<=c<=60

    题解:

    处理出dfs序, 线段树维护.

    1,2操作都对应线段树的一段区间(子树在dfs序中连续), 线段树结点压位记录当前区间的结点包含哪些颜色.

    时间复杂度O(M log N * max(c))

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 400009;
    
    int N, Q, c[maxn];
    int Id[maxn], Left[maxn], Right[maxn], dfn;
    
    struct edge {
    	int t;
    	edge* n;
    } E[maxn << 1], *Pt = E, *H[maxn];
    
    inline void AddEdge(int u, int v) {
    	Pt->t = v, Pt->n = H[u], H[u] = Pt++;
    }
    
    void DFS(int x, int fa = -1) {
    	Id[++dfn] = x;
    	Left[x] = dfn;
    	for(edge* e = H[x]; e; e = e->n)
    		if(e->t != fa) DFS(e->t, x);
    	Right[x] = dfn;
    }
    
    struct Node {
    	Node *lc, *rc;
    	ll v;
    	int mk;
    	inline void pd() {
    		if(~mk) {
    			lc->mk = mk;
    			rc->mk = mk;
    			v = 1LL << mk;
    			mk = -1;
    		}
    	}
    	inline void upd() {
    		if(lc && rc)
    			v = lc->v | rc->v;
    		if(~mk)
    			v = 1LL << mk;
    	}
    } pool[maxn << 1], *pt = pool, *Root;
    
    int L, R, Val;
    
    void Build(Node* t, int l, int r) {
    	int m = (l + r) >> 1;
    	t->mk = -1;
    	if(l != r) {
    		Build(t->lc = pt++, l, m);
    		Build(t->rc = pt++, m + 1, r);
    		t->upd();
    	} else
    		t->v = 1LL << c[Id[m]];
    }
    
    void Modify(Node* t, int l, int r) {
    	if(L <= l && r <= R) {
    		t->mk = Val;
    	} else {
    		int m = (l + r) >> 1;
    		t->pd();
    		L <= m ? Modify(t->lc, l, m) : t->lc->upd();
    		m < R ? Modify(t->rc, m + 1, r) : t->rc->upd();
    	}
    	t->upd();
    }
    
    ll Query(Node* t, int l, int r) {
    	if(L <= l && r <= R) return t->v;
    	int m = (l + r) >> 1;
    	t->pd();
    	t->lc->upd(), t->rc->upd();
    	return (L <= m ? Query(t->lc, l, m) : 0) | (m < R ? Query(t->rc, m + 1, r) : 0);
    }
    
    int calc(ll n) {
    	int ret = 0;
    	for(; n; n -= n & -n) ret++;
    	return ret;
    }
    
    void Work() {
    	DFS(dfn = 0);
    	Build(Root = pt++, 1, N);
    	int t, x;
    	while(Q--) {
    		scanf("%d%d", &t, &x), x--;
    			L = Left[x], R = Right[x];
    		if(t == 1) {
    			scanf("%d", &Val), Val--; 
    			Modify(Root, 1, N);
    		} else
    			printf("%d
    ", calc(Query(Root, 1, N)));
    	}
    }
    
    void Init() {
    	int u, v;
    	scanf("%d%d", &N, &Q);
    	for(int i = 0; i < N; i++)
    		scanf("%d", c + i), c[i]--;
    	for(int i = 1; i < N; i++) {
    		scanf("%d%d", &u, &v);
    		u--, v--;
    		AddEdge(u, v);
    		AddEdge(v, u);
    	}
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in", "r", stdin);
    	freopen("test.out", "w", stdout);
    #endif
    	
    	Init();
    	Work();
    		
    	return 0;
    }
    

    609E. Minimum spanning tree for each edge

    题目大意:

    N个结点, M条无向边, 第i条边连接ui, vi, 边权为wi, 依次输出包含第i条边的最小生成树.

    1<=N,M<=2*10^5, 1<=wi<=10^9.

    题解:

    先跑出任意一个MST(设权值和为tot), 然后建树.

    树链剖分, RMQ维护边权最大值(不需要线段树).

    对于每条边ui, vi, wi, 求出ui~vi路径上的最大边权maxv, 对于这条边的答案就是tot - maxv + wi.

    时间复杂度O(N log N + M log N)

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 200009;
    
    int N, M;
    ll tot, ans[maxn];
    
    struct e {
    	int u, v, w, Id;
    	bool operator < (const e &t) const {
    		return w < t.w;
    	}
    } Edge[maxn];
    
    struct edge {
    	int t, w;
    	edge* n;
    } E[maxn << 1], *pt = E, *H[maxn];
    
    inline void AddEdge(int u, int v, int w) {
    	pt->t = v, pt->w = w, pt->n = H[u], H[u] = pt++;
    }
    
    int par[maxn];
    int Find(int x) {
    	return x == par[x] ? x : par[x] = Find(par[x]);
    }
    
    int RMQ[20][maxn], w[maxn];
    int top[maxn], fa[maxn], Id[maxn], dep[maxn], sz[maxn], ch[maxn];
    int Top, dfn;
    
    void dfs(int x) {
    	sz[x] = 1, ch[x] = -1;
    	for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) {
    		dep[e->t] = dep[x] + 1;
    		fa[e->t] = x;
    		w[e->t] = e->w;
    		dfs(e->t);
    		sz[x] += sz[e->t];
    		if(!~ch[x] || sz[ch[x]] < sz[e->t])
    			ch[x] = e->t;
    	}
    }
    
    void DFS(int x) {
    	top[x] = Top;
    	Id[x] = dfn++;
    	if(~ch[x]) DFS(ch[x]);
    	for(edge* e = H[x]; e; e = e->n)
    		if(e->t != fa[x] && e->t != ch[x]) DFS(Top = e->t);
    }
    
    void Init_Query() {
    	for(int i = 0; i < N; i++)
    		RMQ[0][Id[i]] = w[i];
    	for(int i = 1; (1 << i) <= N; i++)
    		for(int j = 0; j + (1 << i) <= N; j++)
    			RMQ[i][j] = max(RMQ[i - 1][j], RMQ[i - 1][j + (1 << (i - 1))]);
    }
    
    int Qmax(int l, int r) {
    	int Log = log2(r - l + 1);
    	return max(RMQ[Log][l], RMQ[Log][r - (1 << Log) + 1]);
    }
    
    int Query(int x, int y) {
    	int ret = 0;
    	for(; top[x] != top[y]; x = fa[top[x]]) {
    		if(dep[top[x]] < dep[top[y]]) swap(x, y);
    		ret = max(ret, Qmax(Id[top[x]], Id[x]));
    	}
    	if(x == y) return ret;
    	if(dep[x] < dep[y]) swap(x, y);
    	return max(ret, Qmax(Id[y] + 1, Id[x]));
    }
    
    void Work() {
    	tot = 0;
    	sort(Edge, Edge + M);
    	for(int i = 0; i < N; i++) par[i] = i;
    	for(int i = 0; i < M; i++) {
    		int u = Find(Edge[i].u), v = Find(Edge[i].v);
    		if(u != v) {
    			par[u] = v;
    			tot += Edge[i].w;
    			AddEdge(Edge[i].u, Edge[i].v, Edge[i].w);
    			AddEdge(Edge[i].v, Edge[i].u, Edge[i].w);
    			Edge[i].Id += M;
    		}
    	}
    	
    	fa[0] = -1, w[0] = dep[0] = 0;
    	dfs(0);
    	DFS(Top = dfn = 0);
    	Init_Query();
    	
    	for(int i = 0; i < M; i++) if(Edge[i].Id < M) {
    		ans[Edge[i].Id] = tot - Query(Edge[i].u, Edge[i].v) + Edge[i].w;
    	}
    	else
    		ans[Edge[i].Id - M] = tot;
    	for(int i = 0; i < M; i++)
    		cout << ans[i] << "
    ";
    }
    
    void Init() {
    	scanf("%d%d", &N, &M);
    	for(int i = 0; i < M; i++) {
    		scanf("%d%d%d", &Edge[i].u, &Edge[i].v, &Edge[i].w);
    		Edge[i].u--, Edge[i].v--;
    		Edge[i].Id = i;
    	}
    }
    
    int main() {
    	
    	Init();
    	Work();
    	
    	return 0;
    }
    

      

    600D. Area of Two Circles' Intersection

    题目大意:

    给2个圆, 求它们交的面积.

    -10^9<=x,y<=10^9, 1<=r<=10^9

    题解:

    模板题.

    先判掉相离和相切的情况, 然后利用余弦定理与扇形和三角形面积公式解决.

    时间复杂度O(1)

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    typedef long double ld;
    
    void Work() {
    	int x0, x1, y0, y1, r0, r1;
    	scanf("%d%d%d%d%d%d", &x0, &y0, &r0, &x1, &y1, &r1);
    	ld d = sqrt((ld) (x0 - x1) * (x0 - x1) + (ld) (y0 - y1) * (y0 - y1));
    	if(r0 + r1 <= d) {
    		puts("0");
    		return;
    	}
    	if(abs(r0 - r1) >= d) {
    		printf("%.10lf
    ", (double) ld(acos(-1.0)) * min(r0, r1) * min(r0, r1));
    		return;
    	}
    	ld a0 = acos((ld(r0) * r0 + ld(d) * d - ld(r1) * r1) / (d * r0 * 2)); // angle_0
    	ld a1 = acos((ld(r1) * r1 + ld(d) * d - ld(r0) * r0) / (d * r1 * 2)); // angle_1
    
    	printf("%.10lf
    ", (double) (ld(r0) * r0 * (a0 - sin(a0) * cos(a0)) + ld(r1) * r1 * (a1 - sin(a1) * cos(a1))));
    }
    
    int main() {
    	
    	Work();
    	
    	return 0;
    }
    

     

    592D. Super M

    题目大意:

    给棵N个结点的树, 你需要走到其中的M个点, 起始位置任选. 求M个点全都走过的最短路径, 多种方案则选择起始位置的结点字典序小的.

    1<=m<=n<=123456

    题解:

    去掉一些没用的结点与边, 使得保留下来的树的叶子结点全部为需要到达的点.

    记留下来的边总长为x, 起点与终点距离为y, 通过观察(?)可以发现答案为2*x-y(画个图感受一下, 易证).

    所以要最大化y.那么就是在新树中找出1条直径, 并且某一端点字典序最小(多条直径时).

    对于树的直径, 可以使用经典的BFS/DFS做法.

    时间复杂度O(N)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn = 123460;
    
    int n, m;
    bool F[maxn];
    
    struct edge {
    	int t, f;
    	edge* n;
    } E[maxn << 1], *pt = E, *H[maxn];
    
    inline void AddEdge(int u, int v) {
    	pt->t = v, pt->f = 1, pt->n = H[u], H[u] = pt++;
    }
    
    int X, Y, d[maxn], ans;
    
    void dfs(int x, int fa) {
    	d[x] = F[x];
    	for(edge* e = H[x]; e; e = e->n) if(e->t != fa) {
    		dfs(e->t, x);
    		if(!d[e->t]) {
    			e->f = 0;
    		} else
    			d[x] += d[e->t];
    	}
    }
    
    void dfs(int x, int dist, int fa) {
    	d[x] = dist;
    	for(edge* e = H[x]; e; e = e->n)
    		if(e->f && e->t != fa) dfs(e->t, dist + 1, x);
    }
    
    void calc(int x, int fa = -1) {
    	for(edge* e = H[x]; e; e = e->n)
    		if(e->f && e->t != fa) calc(e->t, x), ans += 2;
    }
    
    void Work() {
    	int mx, Id;
    	for(int i = 0; i < n; i++) if(F[i]) {
    		dfs(i, -1);
    		break;
    	}
    	for(int i = 0; i < n; i++) if(F[i]) {
    		dfs(i, 0, -1);
    		break;
    	}
    	mx = 0;
    	for(int i = 0; i < n; i++) if(F[i]) {
    		mx = max(mx, d[i]);
    		if(mx == d[i]) X = i;
    	}
    	dfs(X, 0, -1);
    	mx = 0;
    	for(int i = 0; i < n; i++) if(F[i]) {
    		mx = max(mx, d[i]);
    		if(mx == d[i]) Y = i;
    	}
    	ans = -d[Y], Id = min(X, Y);
    	for(int i = 0; i < n; i++)
    		if(F[i] && d[i] == mx) Id = min(Id, i);
    	dfs(Y, 0, -1);
    	for(int i = 0; i < n; i++)
    		if(F[i] && d[i] == mx) Id = min(Id, i);
    	calc(Y);
    	printf("%d
    %d
    ", ++Id, ans);
    }
    
    void Init() {
    	scanf("%d%d", &n, &m);
    	int u, v;
    	for(int i = 1; i < n; i++) {
    		scanf("%d%d", &u, &v);
    		u--, v--;
    		AddEdge(u, v);
    		AddEdge(v, u);
    	}
    	memset(F, 0, sizeof F);
    	for(int i = 0; i < m; i++) {
    		scanf("%d", &v);
    		F[--v] = true;
    	}
    }
    
    int main() {
    	
    	Init();
    	Work();
    	
    	return 0;
    }
    

    596D. Wilbur and Trees

    题目大意:

    1条线上有N棵位置为xi,高为H的树. 要把它们全部砍下来, 每次随机选择最左边或者最右边的树砍下来. 每棵树倒向左边的概率为p, 假如2棵树之间的距离严格小于H, 那么1棵树向另一棵树方向倒会撞倒另1棵树, 求最后树覆盖线的期望长度. 1<=N<=2000, 1<=H<=10^8, -10^8<=xi<=10^8, 0<=p<=1

    题解:

    期望dp. 先对树的位置排序.

    dp(l, r, ls, rs)表示第l~r棵树没倒, ls,rs分别是第l-1棵树和第r+1棵树的倒向(0左1右).

    枚举第l棵树倒下或者第r棵树倒下(概率均为0.5), 再枚举倒下的方向(概率:左边p, 右边(1-p)), 以此来状态转移.

    时间复杂度O(N^2)

    #include<cstdio>
    #include<cassert>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn = 2009;
    
    bool vis[maxn][maxn][2][2];
    double dp[maxn][maxn][2][2], p;
    int N, H, x[maxn], L[maxn], R[maxn];
    
    double Dp(int l, int r, int ls,int rs) {
    	if(l > r) return 0;
    	double &t = dp[l][r][ls][rs];
    	if(vis[l][r][ls][rs]) return t;
    	vis[l][r][ls][rs] = true;
    	
    	int _l = x[l - 1] + (ls ? H : 0), _L = max(l, L[r]);
    	int _r = x[r + 1] - (rs ? 0 : H), _R = min(r, R[l]);
    	t = p * (min(x[l] - _l, H) + Dp(l + 1, r, 0, rs)) // left -> left
    	  + (1 - p) * (min(_r - x[r], H) + Dp(l, r - 1, ls, 1)); // right -> right
    	t += (1 - p) * (x[_R] - x[l] + min(_r - x[_R], H) + Dp(_R + 1, r, 1, rs)) // left -> right
    	   + p * (x[r] - x[_L] + min(x[_L] - _l, H) + Dp(l, _L - 1, ls, 0)); // right -> left
    	
    	return t *= 0.5;
    }
    
    void Init() {
    	scanf("%d%d%lf", &N, &H, &p);
    	x[0] = -500000000;
    	x[N + 1] = 500000000;
    	for(int i = 1; i <= N; i++) scanf("%d", x + i);
    	sort(x + 1, x + N + 1);
    	memset(vis, 0, sizeof vis);
    	
    	L[0] = 1;
    	for(int i = 1; i <= N; i++)
    		L[i] = (x[i - 1] + H > x[i] ? L[i - 1] : i);
    	R[N + 1] = N;
    	for(int i = N; i >= 1; i--)
    		R[i] = (x[i] + H > x[i + 1] ? R[i + 1] : i);
    }
    
    int main() {
    	
    	Init();
    	printf("%.10lf
    ", Dp(1, N, 0, 1));
    	
    	return 0;
    }
    

    写完啦~~

  • 相关阅读:
    Microsoft Enterprise Library 5.0 系列(二) Cryptography Application Block (初级)
    Microsoft Enterprise Library 5.0 系列(五) Data Access Application Block
    Microsoft Enterprise Library 5.0 系列(八) Unity Dependency Injection and Interception
    Microsoft Enterprise Library 5.0 系列(九) Policy Injection Application Block
    Microsoft Enterprise Library 5.0 系列(三) Validation Application Block (高级)
    软件研发打油诗祝大家节日快乐
    从挖井的故事中想到开发管理中最容易忽视的几个简单道理
    ITIL管理思想的执行工具发布
    管理类软件设计“渔”之演化
    20070926日下午工作流与ITILQQ群 事件管理 讨论聊天记录
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5199528.html
Copyright © 2011-2022 走看看