$$4-7$$
- 第二题是密码锁就直接发出来了,第一题的话又写了一天
- 自己垃圾,无话可说
- 总结一下\(LCT\)简单的子树信息维护要怎么做,以维护子树大小为例,我们对每个子树维护两个信息,一个是子树总大小,一个是虚树的总大小,能够发现我们如果能够快速处理虚树的大小,问题就得到了解决;观察\(LCT\)什么时候会添加、减少虚儿子,\(access \ \ and \ \ link!\),所以在进行这两个操作的时候判断一下就可以了,但是注意这样只能维护可增减的信息,
最大值我就完全不会
- 这道题只需要有大小为\(K\)的联通块,考虑魔法森林的解法,一样从按照\(A\)小到大插入边,维护\(B\)的联通块,可以发现一个联通块有用的信息一定可以表示成一棵树(就是和魔法森林那题差不多),然后考虑能不能试着减少\(B\),如果当前有\(>=K\)的连通块这条最大边是一定没有意义的,因为此时更新的答案一定会比不删这条边的答案优,然后维护\(>=K\)连通块个数以及连通块大小就可以了
- 吐槽:感觉学子树信息就学了半天看了,一中午哑舍下午头都是昏的加上\(LCT\)的代码好久没写又回忆了好久,下午调的时候一直不清醒,晚上状态反而好多了,xjb乱写也能调过,结果最后是\(push\_up\)的时候没注意重新赋初值,然后删边就爆炸了
- 放个代码感慨一下吧
#include <bits/stdc++.h>
typedef std::pair<int, int> PII;
#define a first
#define b second
inline int read(int Num = 0, int Flag = 1)
{
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-')
Flag = -1;
for (; isdigit(ch); ch = getchar())
Num = Num * 10 + ch - '0';
return Num *= Flag;
}
template <typename T> bool chkmax(T &a, T b) { return a < b? a = b, true : false; }
template <typename T> bool chkmin(T &a, T b) { return a > b? a = b, true : false; }
const int mx_n = 3e5 + 5;
const int mx_m = 5e5 + 5;
const int inf = 2e9 + 5;
int N, M, K;
int a[mx_n], b[mx_n];
//int cur;
struct Edge
{
int u, v, wa, wb;
bool operator < (const Edge& rhs)const
{
return wa < rhs.wa;
}
}edge[mx_m];
int tot;
struct Link_Cut_Tree
{
static const int mx_node = (mx_n + mx_m) * 2;
int fa[mx_node];
int ch[mx_node][2];
int isv[mx_node];
int sz_all[mx_node];
int sz_sub[mx_node];
int stk[mx_node];
int rev[mx_node];
PII maxb[mx_node];
inline int prefer(int x)
{
// assert(!isrt(x));
return ch[fa[x]][1] == x;
}
inline bool isrt(int x)
{
return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}
inline void push_up(int h)
{
sz_all[h] = (h <= N) + sz_sub[h];
if (h > N) maxb[h] = PII(edge[h - N].wb, h - N);
else maxb[h] = PII(0, 0);
for (int i = 0; i < 2; ++i) {
chkmax(maxb[h], maxb[ch[h][i]]);
sz_all[h] += sz_all[ch[h][i]];
}
}
inline void push_down(int h)
{
if (rev[h]) {
rev[ch[h][0]] ^= 1, rev[ch[h][1]] ^= 1;
std::swap(ch[h][0], ch[h][1]);
rev[h] = 0;
}
}
void rotate(int x, int ty)
{
int y = fa[x];
if (!isrt(y)) ch[fa[y]][prefer(y)] = x; fa[x] = fa[y];
ch[y][!ty] = ch[x][ty]; fa[ch[x][ty]] = y;
ch[x][ty] = y; fa[y] = x;
push_up(y);
push_up(x);
}
void pass_tag(int u)
{
int top = 0; stk[++top] = u;
for (int i = u; !isrt(i); i = fa[i]) stk[++top] = fa[i];
for (int i = top; i >= 1; --i) push_down(stk[i]);
}
void splay(int h)
{
pass_tag(h);
for (int ty; !isrt(h); rotate(h, !ty)) {
ty = prefer(h);
if (!isrt(fa[h]) && prefer(fa[h]) == ty) rotate(fa[h], !ty);
}
}
void access(int u)
{
for (int v = 0; u; v = u, u = fa[u]) {
splay(u);
sz_sub[u] += sz_all[ch[u][1]];
sz_sub[u] -= sz_all[v];
ch[u][1] = v; push_up(u);
}
// fprintf(stderr, "end\n");
}
void make_root(int u)
{
access(u); splay(u), rev[u] ^= 1;
}
int find(int u)
{
access(u); splay(u);
for (; ch[u][0];) u = ch[u][0];
splay(u);
return u;
}
PII query(int u, int v)
{
make_root(u); access(v), splay(v);
return maxb[v];
}
void cut(int u, int v)
{
// assert(find(u) == find(v));
make_root(u);
access(v);
splay(v);
// if (cur == 6) fprintf(stderr, "!\n");
// assert(ch[v][0] == u);
// assert(v == fa[u]);
// assert(sz_all[u] - sz_sub[u] == 1);
int sz1 = sz_all[u];
int sz0 = sz_all[v] - sz1;
// fprintf(stderr, "%d %d\n", u, v);
tot -= sz_all[v] >= K;
tot += sz1 >= K;
tot += sz0 >= K;
ch[v][0] = 0, fa[u] = 0;
push_up(v);
}
void link(int u, int v)
{
// assert(find(u) != find(v));
make_root(u);
make_root(v);
tot -= sz_all[u] >= K;
tot -= sz_all[v] >= K;
fa[v] = u;
sz_sub[u] += sz_all[v];
push_up(u);
tot += sz_all[u] >= K;
}
}lct;
std::set<PII> S;
bool link(int i)
{
int u = edge[i].u, v = edge[i].v;
int w = edge[i].wb;
if (lct.find(u) == lct.find(v)) {
PII o = lct.query(u, v);
if (o.first <= w) return false;
S.erase(o);
// fprintf(stderr, "%d\n", o.second);
lct.cut(edge[o.second].u, o.second + N);
lct.cut(edge[o.second].v, o.second + N);
}
// fprintf(stderr, "%d %d edge_id = %d\n", u, v, cur);
// assert(lct.find(u) != lct.find(v));
lct.link(u, i + N), lct.link(v, i + N);
return true;
}
bool cut(int i)
{
int a = edge[i].u, b = i + N;
lct.make_root(a);
lct.access(b);
lct.splay(b);
int sz1 = lct.sz_all[a];
int sz0 = lct.sz_all[b] - sz1;
int tot = ::tot;
tot -= lct.sz_all[b] >= K;
tot += sz1 >= K;
tot += sz0 >= K;
if (tot) {
lct.cut(edge[i].u, i + N);
lct.cut(edge[i].v, i + N);
return true;
}
return false;
}
int main()
{
freopen("mincost.in", "r", stdin);
freopen("mincost.out", "w", stdout);
N = read(); M = read(), K = read();
for (int i = 1; i <= N; ++i) {
a[i] = read(), b[i] = read();
}
if (K == 1) {
int ans = inf;
for (int i = 1; i <= N; ++i)
chkmin(ans, a[i] + b[i]);
printf("%d\n", ans);
return 0;
}
for (int i = 1; i <= M; ++i) {
int u = read(), v = read();
int wa = std::max(a[u], a[v]);
int wb = std::max(b[u], b[v]);
edge[i] = (Edge) {u, v, wa, wb};
}
std::sort(edge + 1, edge + M + 1);
int ans = inf;
for (int i = 1; i <= M; ++i) {
// cur = i;
if (link(i)) {
S.insert(PII(edge[i].wb, i));
}
// fprintf(stderr, "%d %d %d\n", i, edge[i].u, edge[i].v);
while (true) {
std::set<PII>::iterator it = --S.end();
if (cut(it->second)) {
S.erase(it);
}
else break;
}
if (tot) {
chkmin(ans, (--S.end())->first + edge[i].wa);
}
}
if (ans >= inf)
printf("no solution\n");
else
printf("%d\n", ans);
// fprintf(stderr, "%lf\n", 1.0 * clock()/CLOCKS_PER_SEC);
return 0;
}