闲话 22.8.12

闲话

好按照时间顺序该《诞生》了。

誕生

ある夏の朝に
某个夏日清晨
もしも神様が
或许老天爷
青空に珈琲を零したら
在蔚蓝天空打翻了咖啡
空を描いてた絵描きが怒るかもね
画着天空的那个画手应该会生气吧
だけど気付くだろう
应该能够注意到的吧
豆色の空も
豆色的天空
悪くはないななんて言うだろう
也不会太糟糕之类的安慰一下
そんなものなのさ
这片辽阔的天空
この広い空ですら
早就是这样的啊

翠の星に乗って
乘着翠绿的星星
あの日のふたりを見に往こう
去看一看那一日的两个人吧
柔らかな雲の そのまた向こう側の
去看那,在柔软的云的更深处的
全ての涙に会いに行こう
所有的泪水

不安そうな顔で
一脸不安地
こちらを見ていた
望向了这边
だから大丈夫と言いたかった
所以才觉得说句没关系就好了
空みたいなもんだよ 人も運命も
其实就像天空一般 人和命运都是

ふたりは羽根になる
两个人化作双翼
翠の星に乗った
乘着翠绿的星星
ふたつの不器用な羽根を
将两个人不灵巧的双翼
包みこむように 身体に宿すように
包裹起来,像寄宿在身体里那样
鯨は凛と歌っている
鲸鱼清澈地唱着歌

翠の星に乗って
乘着翠绿的星星
ふたりはひとつの愛になる
两个人化成了同一份爱
誰も知らない その先は知り得ない
谁也不知道,没法知道从今往后
次の世界を祈っている
祈祷下一个世界里

ふたりの ふたりの
两个人的 两个人的
ふたりの誕生
两个人的诞生

对这首歌我不发表任何评价。
我的语言无法表达我对这首歌思考的万分之一。
请好好听这首歌。这是我对这首歌唯一的评价。
作词/作曲/编曲/调教/演唱/视频制作:春卷饭

今天改题比较快 主要是开网了
虽然《两个人的》是悲剧故事,但是春卷饭在其中讲述的一些哲理还是很有意义的
说到饭式哲理 我又想到《暖暖的星》
可以来jjdw这边看
仔细品味歌词,我们能发现很多有意义的话语

总是会抬头看天。天是很高远的。蓝白色的天上有时会飘过鸟,就像是云。蔚蓝这个词是用来形容天的蓝色的,Cobalt 这个词被翻译成蔚蓝,多亏了Mes的品味。在学氯气时看到了“苍白色火焰”,每次看着天空时也会去寻找这种颜色。有时不用寻找,它会自己跳进我的眼睛里。
我的视线有时会看着现实,有时总是失焦。向内能看到很多美丽的东西,因为我早就接受了不完美的自己。不太能理解那些无法接受自己的人。难道自己不才该是第一个接受烂透了的自己的人吗?
意识流也是很不错的一点,因为只有不经加工的思维才是最真实的原品,那些憋足劲的阅读赏析总是少了一些天性和自我。当然不加修饰的词语总会导致词不达意,请多多包涵。任凭思维跳跃的感觉很棒,只是没有什么人能完全理解。我一直认为自己最好的朋友就是自己。当然我也希望有更多的人想要和我对电波。
又想到了Warma。

一道数据结构题

给定二维平面上的 \(n\) 个矩形,每个矩形以左下角坐标 \((r_1, c_1)\) 与右上角坐标 \((r_2,c_2)\) 给定。定义两个矩形相交当且仅当两个矩形含有某个公共点(只有一个也可以)。构造 \(n\) 个点的无向图 \(G\),每个矩形在其中唯一代表一个点,两个点联通当且仅当对应矩形相交。求 \(G\) 中联通块数量。

\(n,r_i,c_i \le 1e5\),保证 \(r_1< r_2, c_1 < c_2\)

考虑在一棵线段树上维护 \(y\) 上的扫描线。
具体地,我们在每个节点维护覆盖该区间的矩形id、对应矩形的 \(x\) 区间、标明该区间是否被完全覆盖的标记、标明该区间信息是否下传的lazy标记。
具体地,我们首先将矩形按 \(r_1\) 排序,随后在 \(r_1\) 位置查询 \([c_1, c2]\) 区间,并在 \(r_2\) 位置插入 \([c_1,c_2]\) 区间。
讨论查询。由于我们已经处理完左区间 \(\le r_1\) 的矩形的右端点,因此如果查询过程中发现覆盖一个区间的矩形位置 \(\ge r_2\),由于两个矩形肯定在对应被覆盖区间有交,因此二者定相交,合并即可。
讨论修改。我们只需要维护被完全覆盖的区间,打标记并上传即可。

拓展(?)

如上题给定 \(n\) 个矩形。输出 \(n\) 长度的01串,第 \(i\) 位为 1 标明给出的第 \(i\) 个矩形是否可被完全覆盖。

\(n \le 1e5\)

我们发现小矩形的横竖坐标都被大矩形包含,坐标关系是偏序关系,因此考虑cdq分治。
我们首先按 \(r_1\)\(\le\) 偏序关系排序,在cdq分治内部按 \(r_2\)\(\ge\) 偏序关系排序,这样保证左区间扫到的矩形在 \(x\) 维度上包含右区间扫到的矩形。
随后我们进行第三维偏序的处理。对于左矩形,我们在维护 \(\max\) 树状数组下标为 \(c_1\) 的位置插入 \(c_2\)。对于右矩形,我们查询下标 \(\le c_1\) 的部分是否存在大于 \(c_2\) 的数字。若存在,则有包含右矩形的矩形。
这样写简单一些,主要是实现方便。

实现
int Index[N];
void add(int p, int val) {
    while (p <= rmax) {
        Index[p] = max(Index[p], val);
        p += p & -p;
    }
}
void clr(int p) {
    while (p <= rmax) {
        Index[p] = 0;
        p += p & -p;
    }
}
int qry(int p) {
    int ret = 0;
    while (p) {
        ret = max(ret, Index[p]);
        p ^= p & -p;
    } return ret;
}

struct painting {
    int r1, c1, r2, c2;
    bool ck;
    bool operator < (const painting & b) const {
        if (r1 != b.r1) return r1 < b.r1;
        if (r2 != b.r2) return r2 > b.r2;
        return c1 < b.c1;
    }
} p[N], tmp[N];

bool cmp(const painting & a, const painting & b) {
    if (a.r2 != b.r2) return a.r2 > b.r2;
    return a.c1 < b.c1;
}

#define mid (l + r >> 1)
void cdq(int l, int r) {
    if (l == r) return;
    cdq(l, mid), cdq(mid+1, r);
    int i = l, j = mid+1;
    while (j <= r) {
        while (i <= mid and p[i].r2 >= p[j].r2) {
            add(p[i].c1, p[i].c2);
            i++;
        } p[j].ck = (qry(p[j].c1) >= p[j].c2);
        j++;
    } rep(k,l,i-1) clr(p[k].c1);
    merge(p+l, p+mid+1, p+mid+1, p+r+1, tmp+l, cmp);
    memcpy(p+l, tmp+l, sizeof(painting) * (r - l + 1));
}

一道图论题

给定 \(n\) 个点,\(m\) 条边的无向图,边有边权,无重边、自环。请输出含1节点的极小简单环长度。无解输出-1。

\(n,m \le 4e4\)

首先有一个最naive的想法:既然是一个连着1的环,那你可以直接枚举1节点的出边,设当前出边为 \((1,v,d)\)。删除这条边并跑最短路,用 \(dis[v] + d\) 更新答案。这样做的正确性显然。然而时间复杂度不是很好。设1节点的度为 \(k\),若使用堆优化dijkstra,我们有最劣时间复杂度为 \(O(km\log n)\)。这在菊花妈妈课堂图中显然不可行。

我们发现,更新答案的总复杂度是 \(O(k)\) 的,而单次跑最短路的复杂度是 \(O(m\log n)\) 的。考虑如何减小跑最短路的次数。

我们按输入边的顺序为边排序,每条边唯一得到一个 \([1,m]\) 内的整数编号。

\(\text{Lemma 1}\)

任意两条边的编号彼此不同。

显然。

\(\text{Lemma 2}\)

任意两条不同的边的编号定有一位二进制位彼此不同。

由引理1得证。

\(\text{Lemma 3}\)

任意一个可为答案贡献的环中,有且仅有两条边的一个端点为 1 节点。

由简单环的性质显然。
由引理 3,定义一个环的两个编号为其中端点为 1 节点的两条边的编号。

\(\text{Theorem}\)

对于任意一个含1节点的环,存在一位二进制位使得这个环的两个编号中这一位的01性不同。

因此,我们可以通过每次将与1相连的边中编号特定位为1的全体删除,跑最短路并逐边枚举答案的方式得到所有可能成为最终答案的答案。
由于只需进行 \(O(\log k)\) 次最短路算法,并 \(k = O(m)\),因此总复杂度为 \(O(m \log n \log m)\)

使用了dij的代码
struct node {
    int eid, nid, dis;
}; vector<node> tmp;

#define Aster(s) for ( register int i = head[s]; i; i = e[i].next )
#define v e[i].to
#define d e[i].dis
int head[N], mlc;
struct ep {
    int to, next, dis, id;
} e[N<<3];
inline void adde(int f, int t, int ds, int id) {
    e[++mlc].to = t;
    e[mlc].next = head[f];
    e[mlc].dis  = ds;
    e[mlc].id = id;
    head[f] = mlc;
}

int dis[N];
bool vis[N], del[N<<2];
struct pid {
    int id, dis;
    bool operator < (const pid & b) const {
        return dis > b.dis;
    }
}; priority_queue<pid> q;
void dij() {
    rep(i,1,n) dis[i] = 0x3f3f3f3f, vis[i] = false;
    dis[1] = 0; q.push(pid{1, 0});
    while (!q.empty()) {
        int u = q.top().id; q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        Aster(u) {
            if (del[e[i].id]) continue;
            if(dis[v] > dis[u] + d) {
                dis[v] = dis[u] + d;
                q.push(pid{v, dis[v]});
            }
        }
    }
}

get(n), get(m);
rep(i,1,n) head[i] = 0; mlc = 0; tmp.clear();
rep(i,1,m) {
    get(t1), get(t2), get(t3);
    adde(t1, t2, t3, i);
    adde(t2, t1, t3, i);
    if(t1 == 1 or t2 == 1) {
        tmp.push_back(node{i, (t1 == 1) ? t2 : t1, t3});
    }
} ans = 0x3f3f3f3f; 
for (int i = 0; i <= __lg(m); i++) {
    for (auto x : tmp) if (x.eid & (1<<i)) del[x.eid] = 1;
    dij();
    for (auto x : tmp) if (x.eid & (1<<i)) {
        del[x.eid] = 0;
        ans = min(ans, x.dis + dis[x.nid]);
    } 
}printf("%d\n", ans == 0x3f3f3f3f ? -1 : ans);
posted @ 2022-08-12 19:42  joke3579  阅读(51)  评论(1编辑  收藏  举报