四连测Day1

一道大暴力被人说做法雷同...真的是醉了

T1 树上路径最小值(min)

给一棵树,多次询问两点间路径上点权最小值

sol:树链剖分 倍增 平衡树(划掉)

瞎J2乱做都可以

然而太困了爆零

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 1e5 + 777;
int n;
int first[maxn],to[maxn << 1],next[maxn << 1],cnt;
int a[maxn],size[maxn],bl[maxn],fa[maxn],depth[maxn],dfn;
int pos[maxn],reh[maxn];
inline void add(int u,int v)
{
    to[++cnt] = v;next[cnt] = first[u];first[u] = cnt;
}
inline void ins(int u,int v){add(u,v);add(v,u);}
inline void dfs1(int u)
{
    size[u] = 1;
    for(int i=first[u];i;i=next[i])
    {
        if(to[i] == fa[u])continue;
        fa[to[i]] = u;dfs1(to[i]);depth[to[i]] = depth[u] + 1;size[u] += size[to[i]];
    }
}
inline void dfs2(int u,int col)
{
    int k = 0;pos[u] = ++dfn;reh[pos[u]] = u;bl[u] = col;
    for(int i=first[u];i;i=next[i])
        if(to[i] != fa[u] && size[to[i]] > size[k])k = to[i];
    if(!k)return;
    dfs2(k,col);
    for(int i=first[u];i;i=next[i])
        if(to[i] != fa[u] && k != to[i])dfs2(to[i],to[i]);
}
int seg[maxn << 2];
#define ls (x << 1)
#define rs ((x << 1) | 1)
inline void update(int x,int l,int r,int pos,int val)
{
    if(l == r)
    {
        seg[x] = val;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid)update(ls,l,mid,pos,val);
    else update(rs,mid + 1,r,pos,val);
    seg[x] = min(seg[ls],seg[rs]);
}
inline int query(int x,int l,int r,int L,int R)
{
    if(L <= l && r <= R)return seg[x];
    int mid = (l + r) >> 1,ans = 2147483233;
    if(L <= mid)ans = min(ans,query(ls,l,mid,L,R));
    if(R > mid)ans = min(ans,query(rs,mid + 1,r,L,R));
    return ans;
}

int main()
{
    freopen("min.in","r",stdin);
    freopen("min.out","w",stdout);
    int q;
    for(int i=1;i<maxn * 4;i++)seg[i] = 2147483233;
    n = read();q = read();
    for(int i=1;i<=n;i++)a[i] = read();
    for(int i=2;i<=n;i++)
    {
        int u = read(),v = read();
        ins(u,v);
    }dfs1(1);dfs2(1,1);
    for(int i=1;i<=n;i++)update(1,1,n,pos[i],a[i]);
    while(q--)
    {
        int u = read(),v = read();int ans = 2147483233;
        while(bl[u] != bl[v])
        {
            if(depth[bl[u]] < depth[bl[v]])swap(u,v);
            ans = min(ans,query(1,1,n,pos[bl[u]],pos[u]));
            u = fa[bl[u]];
        }
        if(pos[u] > pos[v])swap(u,v);
        ans = min(ans,query(1,1,n,pos[u],pos[v]));
        printf("%d
",ans);
    }
}
爆炸代码(0分)
#include<iostream>
#include<cstring>
#include<cstdio>
#define MAXN 131072
using namespace std;
inline int read()
{
    int x=0,t=1,c;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    while(isdigit(c))x=x*10+c-'0',c=getchar();
    return x*t;
}
int n,q;
int a[MAXN];
int first[MAXN],targ[MAXN<<1],nxt[MAXN<<1],cnte=1;
int anc[MAXN][22],minv[MAXN][22],deep[MAXN];
void AddEdge(int u,int v)
{
    targ[cnte]=v;nxt[cnte]=first[u];first[u]=cnte++;swap(u,v);
    targ[cnte]=v;nxt[cnte]=first[u];first[u]=cnte++;
}
void DFS(int x=1,int Fa=0)
{
    anc[x][0]=Fa;
    minv[x][0]=min(a[x],a[Fa]);
    for(int i=1;i<20;i++)
    {
        anc[x][i]=anc[anc[x][i-1]][i-1];
        minv[x][i]=min(minv[x][i-1],minv[anc[x][i-1]][i-1]);
    }
    for(int i=first[x];i;i=nxt[i])
    {
        if(targ[i]!=Fa)
        {
            deep[targ[i]]=deep[x]+1;
            DFS(targ[i],x);
        }
    }
}
void Jump(int &x,int f,int &r)
{
    r=min(r,minv[x][f]);
    x=anc[x][f];
}
int LCA(int x,int y)
{
    int ret=min(a[x],a[y]);
    if(deep[x]<deep[y])swap(x,y);
    for(int i=19;i>=0;i--)
    {
        if((1<<i)<=deep[x]-deep[y])Jump(x,i,ret);
    }
    for(int i=19;i>=0;i--)if(anc[x][i]!=anc[y][i])Jump(x,i,ret),Jump(y,i,ret);
    if(x!=y)Jump(x,0,ret),Jump(y,0,ret);
    //printf("%d %d
",x,y);
    return ret;
}
int main()
{
    freopen("min.in","r",stdin);
    freopen("min.out","w",stdout);
    n=read(),q=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<n;i++)AddEdge(read(),read());
    deep[1]=1;
    DFS();
    for(int i=0;i<q;i++)
    {
        printf("%d
",LCA(read(),read()));
    }
}
/*
7 7
1 2 3 4 5 6 7
1 2
2 4
3 2
4 6
5 6
6 7
1 7
2 6
3 5
1 2
3 4
5 6
4 7
*/
std

T2 k大异或和

给一个数组a,求a中第k小的非空子序列异或和

n<=1e4

sol:记录一下当前的是第几大,具体可以通过一个桶前缀和来搞,然后upperbound

高二的几个小伙伴都是这么写的于是被D了

标算是桶排序。。。

无语

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 1e4 + 10;
int n,q,k;
int a[maxn],s[maxn];
int sum[1049000];
int main()
{
    freopen("xor.in","r",stdin);
    freopen("xor.out","w",stdout);
    n = read(),q = read();
    for(int i=1;i<=n;i++)a[i] = read(),s[i] = s[i - 1] ^ a[i];
    for(int i=0;i<n;i++)
        for(int j=i + 1;j<=n;j++)sum[s[i] ^ s[j]]++;
    for(int i=1;i<=1048576;i++)sum[i] += sum[i - 1];
    while(q--)
    {
        int k = read();
        printf("%d
",upper_bound(sum,sum + 1048576,k - 1) - sum);
    }
}
View Code

T3 最小生成树

给n个点,m条计划,每条计划是在[l,r]中任意点连边

每连一条边需要vi的代价

求把所有点连通的最小代价

sol:线段树 + 贪心

发现连的边一定是当前vi最小的边,于是把计划按vi从大到小排序,每次区间覆盖,最后输出一下整棵树的和就可以了

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 1e5 + 10;
int n,q;
int tag[maxn << 2],sum[maxn << 2],vis[maxn << 2];
struct proj
{
    int l,r,v;
    bool operator < (const proj &b)const
    {
        return v > b.v;
    }
}p[maxn];
#define ls (x << 1)
#define rs ((x << 1) | 1)
inline void pushup(int x)
{
    sum[x] = sum[ls] + sum[rs];
}
inline void pushdown(int x,int l,int r)
{
    if(tag[x])
    {
        int mid = (l + r) >> 1;
        tag[ls] = tag[x];tag[rs] = tag[x];
        sum[ls] = tag[x] * (mid - l + 1);sum[rs] = tag[x] * (r - mid);
        tag[x] = 0;
    }
    if(vis[x])vis[ls] = vis[rs] = 1;
}
inline void update(int x,int l,int r,int L,int R,int val)
{
    if(L <= l && r <= R)
    {
        tag[x] = val;
        sum[x] = val * (r - l + 1);
        vis[x] = 1;
        return;
    }
    pushdown(x,l,r);
    int mid = (l + r) >> 1;
    if(L <= mid)update(ls,l,mid,L,R,val);
    if(mid < R)update(rs,mid + 1,r,L,R,val);
    sum[x] = sum[ls] + sum[rs];
    vis[x] = vis[ls] & vis[rs];
}
int main()
{
    freopen("kruskal.in","r",stdin);
    freopen("kruskal.out","w",stdout);
    n = read() - 1,q = read();
    for(int i=1;i<=q;i++)p[i].l = read(),p[i].r = read() - 1,p[i].v = read();
    sort(p + 1,p + q + 1);
    int ans = 0;
    for(int i=1;i<=q;i++)update(1,1,n,p[i].l,p[i].r,p[i].v);
    if(!vis[1])cout<<-1;
    else cout<<sum[1];
}
View Code

orz

诅咒:树剖永远写挂

我真是!$^$&!&*!%*%&*!*&$!&

upd:有人引用了我的题解

他好懒

但是他ak了

太强了

%%%

原文地址:https://www.cnblogs.com/Kong-Ruo/p/9436751.html