一些题目小结6.29

1.2588: Spoj 10628. Count on a tree
树上不修改第k大。
迷之RE的原因是被精妙地炸掉了intQAQ
然后又PE
然后才A
我想知道bzoj的人是不是蛇精病。。。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define Rep(i,n) for(int i = 1;i <= n;i ++)
#define RepG(i,x) for(int i = head[x];~ i;i = edge[i].next)
#define v edge[i].to
#define u t[x]
#define o t[y]
#define e t[z]
#define s t[p]
#define mid ((long long)l + r >> 1)
#define lson u.lc,l,mid,o.lc
#define rson u.rc,mid + 1,r,o.rc
using namespace std;
const int N = 100005;
const int inf = (1ll << 31) - 5;
struct Tree{int lc,rc,cnt;}t[N * 40];
struct Edge{int next,to;}edge[N << 1];
int top[N],rt[N],dep[N],fa[N],sz[N],n,m,a[N],cnt,head[N],val,son[N],tot;
void save(int a,int b){edge[cnt] = (Edge){head[a],b},head[a] = cnt ++;}
void dfs(int x){sz[x] = 1;RepG(i,x)if(v != fa[x]){fa[v] = x,dep[v] = dep[x] + 1,dfs(v),sz[x] += sz[v];if(sz[v] > sz[son[x]])son[x] = v;}}
void dfs(int x,int tp){top[x] = tp;if(son[x])dfs(son[x],tp);RepG(i,x)if(v != fa[x] && v != son[x])dfs(v,v);}
void Ins(int &x,int l,int r,int y){x = ++ tot;u = o;u.cnt ++;if(l == r)return;val <= mid ? Ins(lson) : Ins(rson);}
void ReBuild(int x){val = a[x];Ins(rt[x],0,inf,rt[fa[x]]);RepG(i,x)if(v != fa[x])ReBuild(v);}
int lca(int x,int y)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]])swap(x,y);
        x = fa[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
int Qry(int x,int l,int r,int y,int z,int p,int k)
{
    if(l == r)return l;
    int res = t[u.lc].cnt + t[o.lc].cnt - t[e.lc].cnt - t[s.lc].cnt;
    if(res >= k)return Qry(lson,e.lc,s.lc,k);
    else return Qry(rson,e.rc,s.rc,k - res);
}
int main ()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    Rep(i,n)scanf("%d",&a[i]);
    Rep(i,n - 1){int x,y;scanf("%d%d",&x,&y);save(x,y),save(y,x);}
    int ls = 0;
    dfs(1),dfs(1,1);
    ReBuild(1);
    Rep(i,m)
    {
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        x ^= ls;
        int z = lca(x,y),p = fa[z];
        printf("%d",ls = Qry(rt[x],0,inf,rt[y],rt[z],rt[p],k));
        if (i != m) puts ("");
    }
    return 0;
}

2.2326: [HNOI2011]数学作业
显然的递推式是:
f[i]=f[i1]10kmodM+imodM
然后我上节课学习了矩阵乘法,刚好来应用一下:

Fnn1=10k00110111Fn1n11

哦然后昨天fsf跟我说:你先发出去我看看排版。
然后我就忘了继续写了QAQ
还被琦爷D了QAQ
代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define Rep(i,n) for(int i = 1;i <= n;i ++)
using namespace std;
long long n;
int M;
struct Matrix{long long a[5][5];};
Matrix Init(){Matrix k;memset(k.a,0,sizeof(k.a));return k;}
Matrix operator*(Matrix x,Matrix y)
{
    Matrix c = Init();
    Rep(i,3)Rep(k,3)Rep(j,3)c.a[i][j] = (c.a[i][j] + ((x.a[i][k] % M) * (y.a[k][j] % M)) % M) % M;
    return c;
}
void print(Matrix c)
{
    Rep(i,3){Rep(j,3)printf("%lld ",c.a[i][j]);puts("");}
}
Matrix FP(Matrix w,long long p)
{
    //print(w);
    //printf("%lld\n",p);
    Matrix c = Init();
    Rep(i,3)c.a[i][i] = 1;
    while(p)
    {
        if(p & 1)c = c * w;
        p >>= 1;
        w = w * w;
    }
    return c;
}
int main ()
{
    scanf("%lld%d",&n,&M);
    Matrix c,ans;
    c = Init(),ans = Init();
    c.a[1][2] = 1,c.a[1][3] = 1,c.a[2][2] = 1,c.a[2][3] = 1,c.a[3][3] = 1;
    ans.a[3][1] = 1;
    for(long long i = 1,k = 1;i <= n;i *= 10,k ++)
    {
        long long j = min(i * 10 - 1,n);
        c.a[1][1] = (long long)pow(10,k);c.a[1][2] = c.a[1][3] = c.a[2][3] = c.a[2][2] = c.a[3][3] = 1;
        c = FP(c,j - i + 1);
        ans = c * ans;
    }
    printf("%lld\n",ans.a[1][1]);
    return 0;
}

3.虽然是奶牛题然而感觉还是很可做
(至少感觉思路很好)
Farmer John打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务。于是,FJ必须为此向电信公司支付一定的费用。 FJ的农场周围分布着 N(1<=N<=1,000)1..N 顺次编号的废弃的电话线杆,任意两根电话线杆间都没有电话线相连。一共 P(1<=P<=10,000) 对电话线杆间可以拉电话线,其余的那些由于隔得太远而无法被连接。 第i对电话线杆的两个端点分别为 AiBi ,它们间的距离为 Li(1<=Li<=1,000,000) 。数据中保证每对 AiBi 最多只出现1次。编号为1的电话线杆已经接入了全国的电话网络,整个农场的电话线全都连到了编号为N的电话线杆上。也就是说,FJ的任务仅仅是找一条将1号和N号电话线杆连起来的路径,其余的电话线杆并不一定要连入电话网络。 经过谈判,电信公司最终同意免费为FJ连结 K(0<=K<N) 对由FJ指定的电话线杆。对于此外的那些电话线,FJ需要为它们付的费用,等于其中最长的电话线的长度(每根电话线仅连结一对电话线杆)。如果需要连结的电话线杆不超过 K <script id="MathJax-Element-439" type="math/tex">K</script>对,那么FJ的总支出为0。 请你计算一下,FJ最少需要在电话线上花多少钱。
题解:思路很明确是二分答案,然后问题是之后怎么办。
之后显然是把>W的那些边都变成1,其余变为0跑一下最短路就成了。
这个题的思路其实很像HeoiD1T2我会说。。。?

#include <cstdio>
#include <cstring>
#include <algorithm>
#define Rep(i,n) for(int i = 1;i <= n;i ++)
#define v edge[i].to
#define RepG(i,x) for(int i = head[x];~ i;i = edge[i].next)
using namespace std;
const int N = 1005;
struct Edge{int next,to,w;}edge[N * 20];
int n,m,K,dis[N],head[N],q[N * 40],cnt;bool vis[N];
void save(int a,int b,int c){edge[cnt] = (Edge){head[a],b,c},head[a] = cnt ++;}
bool spfa(int ans)
{
    memset(dis,127,sizeof(dis));
    int h,t;
    dis[1] = 0;h = 0,t = 1,q[0] = 1;vis[1] = 1;
    while(h != t)
    {
        int x = q[h ++];
        if(h == 1024)h = 0 ;
        RepG(i,x)
            if(dis[v] > dis[x] + (bool)(edge[i].w > ans))
            {
                dis[v] = dis[x] + (bool)(edge[i].w > ans);
                if(!vis[v])q[t ++] = v,vis[v] = 1;
                if(t == 1024)t = 0;
            }
        vis[x] = 0;
    }
    return dis[n] <= K;
}
int main ()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&m,&K);   
    Rep(i,m)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        save(a,b,c),save(b,a,c);
    }
    int l = 0,r = 1000001,ans = -1;
    while(l <= r)
    {
        int mid = l + r >> 1;
        if(spfa(mid))ans = mid,r = mid - 1;
        else l = mid + 1;
    }
    printf("%d",ans);
    return 0;
}

4.每年万圣节,威斯康星的奶牛们都要打扮一番,出门在农场的N(1≤N≤100000)个牛棚里转悠,来采集糖果.她们每走到一个未曾经过的牛棚,就会采集这个棚里的1颗糖果. 农场不大,所以约翰要想尽法子让奶牛们得到快乐.他给每一个牛棚设置了一个“后继牛棚”.牛棚i的后继牛棚是Xi.他告诉奶牛们,她们到了一个牛棚之后,只要再往后继牛棚走去,就可以搜集到很多糖果.事实上这是一种有点欺骗意味的手段,来节约他的糖果. 第i只奶牛从牛棚i开始她的旅程.请你计算,每一只奶牛可以采集到多少糖果.
窝看到第一眼的时候:
SB题,一眼秒。
然后就WA了。。。
然而大体思路是对的只不过自己智障写挂了QAQ
首先缩点并且重建整个图,考虑到在一个scc上的点可以获得它的所有后继的答案,那么我们记忆化搜索一发即可。
然后就没有了QAQ

#include <cstdio>
#include <cstring>
#include <algorithm>
#define Rep(i,n) for(int i = 1;i <= n;i ++)
#define RepG(i,x) for(int i = head[x];~ i;i = edge[i].next)
using namespace std;
const int N = 100005;
int to[N],n,cnt,head[N],dfn[N],stk[N],tp,low[N],dsz,scc,bel[N],sz[N];
bool vis[N],del[N];
struct Edge{int next,to;}edge[N];
void save(int a,int b){edge[cnt] = (Edge){head[a],b},head[a] = cnt ++;}
void dfs(int x)
{
    dfn[stk[++ tp] = x] = low[x] = ++ dsz;int y;
    int v = to[x];
    if(!dfn[v])dfs(v),low[x] = min(low[v],low[x]);
    else if(!del[v])low[x] = min(dfn[v],low[x]);
    if(dfn[x] == low[x]){++ scc;do{bel[y = stk[tp --]] = scc,sz[scc] ++;del[y] = 1;}while(y != x);}
}
#define v edge[i].to
int ans[N];
void ReBuild(){Rep(i,n)if(bel[i] != bel[to[i]])save(bel[i],bel[to[i]]);}
int ReDfs(int x)
{
    if(ans[x])return ans[x];
    ans[x] = sz[x];
    RepG(i,x)ans[x] += ReDfs(v);
    return ans[x];
}
int main ()
{
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    Rep(i,n)scanf("%d",&to[i]);
    Rep(i,n)if(!dfn[i])dfs(i);
    ReBuild();
    Rep(i,n)printf("%d\n",ReDfs(bel[i]));
    return 0;
}

剩下A的几道题都是窝东拼西凑凑出的水题QAQ
哦其实我上面几道题也是水题QAQ
真是颓废的一天QAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值