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\n", 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] << "\n";
} 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\n", (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\n", (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\n%d\n", ++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\n", Dp(1, N, 0, 1)); return 0;
}
写完啦~~
codeforces 几道题目的更多相关文章
- C语言超级经典400道题目
C语言超级经典400道题目 1.C语言程序的基本单位是____ A) 程序行 B) 语句 C) 函数 D) 字符.C.1 2.C语言程序的三种基本结构是____构A.顺序结构,选择结构,循环结 B.递 ...
- hdu 动态规划(46道题目)倾情奉献~ 【只提供思路与状态转移方程】(转)
HDU 动态规划(46道题目)倾情奉献~ [只提供思路与状态转移方程] Robberies http://acm.hdu.edu.cn/showproblem.php?pid=2955 背包 ...
- 小白欢乐多——记ssctf的几道题目
小白欢乐多--记ssctf的几道题目 二哥说过来自乌云,回归乌云.Web400来源于此,应当回归于此,有不足的地方欢迎指出. 0x00 Web200 先不急着提web400,让我们先来看看web200 ...
- 在 n 道题目中挑选一些使得所有人对题目的掌握情况不超过一半。
Snark and Philip are preparing the problemset for the upcoming pre-qualification round for semi-quar ...
- SQL的几道题目
1.构造数据插入方案表t_project_finish表 a)将addtime更新为当前时间的前一天 首先想到的是addtime=addtime-1,然后就开始验证这个想法. 插入一行数据,包括主键和 ...
- leetcode 几道题目
是周六晚上的几道题,晚上11点半,睡的早,起不来! 494. Target Sum 分析:看完这题,看到数据范围,长度20,枚举就是1<<20 = 1e6, 然后单次20,总共就是2e8, ...
- GDOI2015的某道题目
分析: 考试的时候由于一些神奇的原因(我就不说是什么了)...没有想$C$题,直接交了个暴力上去... 然后发现暴力的数组开的太大,由于矩阵乘法的需要做$m$次初始化,所以只拿到了10分... 我们一 ...
- C++面试出现频率最高的30道题目
http://blog.csdn.net/wangshihui512/article/details/9092439 1.new.delete.malloc.free关系 delete会调用对象的析构 ...
- 从几道题目带你深入理解Event Loop_宏队列_微队列
目录 深入探究JavaScript的Event Loop Event Loop的结构 回调队列(callbacks queue)的分类 Event Loop的执行顺序 通过题目来深入 深入探究Java ...
随机推荐
- Angular之filter学习
过滤器(filter)正如其名,作用就是接收一个输入,通过某个规则进行处理,然后返回处理后的结果.主要用在数据的格式化上,例如获取一个数组中的子集,对数组中的元素进行排序等.ng内置了一些过滤器,它们 ...
- 为net-snmp添加读readTimeTicks
function readTimeTicks(time){ if(time === 0) return ''; var d = 0, h = 0, m = 0, s = 0; d = parseInt ...
- javascript 控制input
1.只允许输入数字 <input name="username" type="text" onkeyup="value=this.val ...
- mac版gif格式录屏工具下载和使用
下载链接: http://pan.baidu.com/s/1geeRmtd 密码: rstv ps:如果失效可以联系发邮件至chenruichn@163.com联系我 [以下教程为转载]本帖最后由 S ...
- Java IO 和 NIO
昨天面试问到了有关Java NIO的问题,没有答上来.于是,在网上看到了一篇很有用的系列文章讲Java IO的,浅显易懂.后面的备注里有该系列文章的链接.内容不算很长,需要两个小时肯定看完了,将该系列 ...
- Visual Studio 2008快捷键
命令行:Devenv 启动VS StudionIsqlw 启动SQL2000查询分析器Sqlwb 启动SQL2005企业管理器Inetmgr 启动IIS管理器大纲Ctrl+M,O折叠所有大纲Ctrl+ ...
- paul的cnblog,欢迎大家的光临
我会在blog里面分享各种资源,技术文章,大家多多交流,欢迎拍砖.
- Piggy-Bank (hdoj1114)
Piggy-Bank Problem Description Before ACM can do anything, a budget must be prepared and the necessa ...
- VS2012编译Snmp++ v3.2.25
VS2012编译Snmp++ v3.2.25跟用VC6/VC2010等编译方法区别不大. 网上和教程上盛传的方式是把snmp++的cpp源文件和头文件都加到工程里,再编译.我觉得添加所有头文件到工程里 ...
- 走出MFC子类化的迷宫
走出MFC子类化的迷宫 KEY WORDS:子类化 SUBCLASSWINDOW MFC消息机制 许多Windows程序员都是跳过SDK直接进行RAD开发工具[或VC,我想VC应不属于RAD]的学习 ...