接水果【题解】

前言

虽然是NOI-/NOI/CTSC,但感觉还没有平时考试难,可能是这种题太套路了.

题面

给了你一棵树,给了你一些路径,每次询问,u,v两点间的第k小的子路径(必须是给出的那些路径中的)

sol

怎么判某条路径是某条路径的子路径?
一个套路就是用dfs序的区间包含关系.这个套路大概自己推理一下就出来了.
然后发现限制条件是一个二维的,所以这个区间不是一个线段,而是一个矩形,所以用一下扫描线.当然可以用树套树,二维树状数组,但是他们大材小用。注意到不需要修改,而这些数据结构支持修改,所以不需要用。
扫描线就是把一个矩形拆成两条线段,分别是平行于y轴的两条.每个线段记录一下横坐标,记录一下两个纵坐标,然后在记录一下是左边的还是右边的。然后按x排序然后顺次加入,计入左边的就给y1-y2加一,计入右边的就减一.

code

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
template <class T>
inline void read(T&data){
    register char ch=0;
    data=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch<='9'&&ch>='0'){
        data=(data<<3)+(data<<1)+(ch^48);
        ch=getchar();
    }
    return;
}
#define rg register
const int _ = 100011;
struct edge {
    int nt,to;
}e[_<<1];
int cnt=0,n,head[_],m,q,son[_],size[_],top[_],fa[_],deep[_],Index,dfn[_],low[_];
int Map[_],ans[_];
struct Line{
    int ki,x,y1,y2,d,val;
}Q[_<<2],Q1[_<<2],Q2[_<<2];
int tree[_<<2];
inline int lowbit(register int k){return k&(-k);}
inline void modify(register int loc,register int zh){for(register int i=loc;i<=Index+1;i+=lowbit(i))tree[i]+=zh;}
inline int query(register int loc){register int ret=0;for(register int i=loc;i;i-=lowbit(i))ret+=tree[i];return ret;}
void add(register int a,register int b){e[++cnt].to=a,e[cnt].nt=head[b],head[b]=cnt;}
bool cmp(Line a,Line b){return a.val<b.val;}
bool cmp2(Line a,Line b){if(a.x!=b.x)return a.x<b.x;return a.ki<b.ki;}
void dfsI(register int now,register int ff){
    deep[now]=deep[ff]+1,fa[now]=ff,size[now]=1;
    for(register int i=head[now];i;i=e[i].nt)if(e[i].to!=ff){
            dfsI(e[i].to,now);size[now]+=size[e[i].to];
            if(size[e[i].to]>size[son[now]])son[now]=e[i].to;
        }
}
void dfsII(register int now,register int topf){
    dfn[now]=++Index,top[now]=topf;
    if(son[now])dfsII(son[now],topf);
    for(register int i=head[now];i;i=e[i].nt)if(dfn[e[i].to]==0)dfsII(e[i].to,e[i].to);
    low[now]=++Index;
}
inline int getlca(register int a,register int b,register int &yl){
    while(top[a]^top[b]){
        if(deep[top[a]]<deep[top[b]]) swap(a,b);
        yl=top[a],a=fa[top[a]];
    }
    if(deep[a]<deep[b])swap(a,b);
    if(a!=b)
    yl=son[b];
    return b;
}
inline void Insert(register int a,register int b,register int c,register int d,register int e,register int f){
        Q[++cnt].ki=a,Q[cnt].x=b,Q[cnt].y1=c,Q[cnt].y2=e,Q[cnt].val=f,Q[cnt].d=1;
        Q[++cnt].ki=a,Q[cnt].x=d+1,Q[cnt].y1=c,Q[cnt].y2=e,Q[cnt].val=f,Q[cnt].d=-1;
}
void divide(register int l,register int r,register int L,register int R){
    //cout<<l<<' '<<r<<endl;
    if(l==r){
        for(register int i=L;i<=R;++i)
            if(Q[i].ki==2)
                ans[Q[i].y2]=l;
        return;
    }
    register int mid = (l+r)>>1;
    register int t1=0,t2=0;
    for(register int i=L;i<=R;++i){
        if(Q[i].ki==1){
            if(Q[i].val<=mid)   Q1[++t1]=Q[i],modify(Q[i].y1,Q[i].d),modify(Q[i].y2+1,-Q[i].d);
            else Q2[++t2]=Q[i];
        }
        else {
            register int su=query(Q[i].y1);
            if(Q[i].d<=su){Q1[++t1]=Q[i];/*cout<<Q[i].y2<<' '<<mid<<'l'<<endl;*/}
            else Q[i].d-=su,Q2[++t2]=Q[i]/*,cout<<Q[i].y2<<' '<<mid<<'r'<<endl*/;
        }
    }
    for(register int i=1;i<=t1;++i)Q[i+L-1]=Q1[i];
    for(register int i=1;i<=t2;++i)Q[t1+L-1+i]=Q2[i];
    divide(l,mid,L,L+t1-1),divide(mid+1,r,L+t1,R);return;
}
int main(){
    //freopen("data.in","r",stdin);
    //freopen("1.out","w",stdout);
    register int a,b,c;
    read(n),read(m),read(q);
    for(rg int i=1;i<n;++i){
        read(a),read(b);
        add(a,b),add(b,a);
    }
    dfsI(1,0);dfsII(1,1);cnt=0;
    for(register int i=1;i<=m;++i){
        read(a),read(b),read(c);
        if(dfn[a]>dfn[b])swap(a,b);
        register int yl=0,lca=getlca(a,b,yl);//cout<<yl<<endl;
        if(lca==a){
            if(dfn[yl]>=1)Insert(1,dfn[b],1,low[b],dfn[yl]-1,c);
            //if(dfn[yl]<Index)Insert(1,dfn[b],low[yl],low[b],Index,c);
            if(yl)Insert(1,low[yl],dfn[b],Index,low[b],c);
        }
        else Insert(1,dfn[b],dfn[a],low[b],low[a],c);
    }
    //exit(0);
    /*for(register int i=1;i<=cnt;++i){
        cout<<Q[i].x<<' '<<Q[i].y1<<' '<<Q[i].y2<<endl;
        }*/
    a=-1,b=0;
    sort(Q+1,Q+cnt+1,cmp);
    for(register int i=1;i<=cnt;++i){
        if(Q[i].val==a) Q[i].val=b;
        else Map[++b]=Q[i].val,a=Q[i].val,Q[i].val=b;
    }
    //cout<<endl;
    register int yl=b;
    for(register int i=1;i<=q;++i){
        read(a),read(b),read(c);
        if(dfn[a]>dfn[b])swap(a,b);
        Q[++cnt].ki=2,Q[cnt].x=dfn[b],Q[cnt].y1=dfn[a],Q[cnt].y2=i,Q[cnt].d=c;
    }
    sort(Q+1,Q+cnt+1,cmp2);b=yl;
    divide(1,b,1,cnt);
    for(register int i=1;i<=q;++i){
        cout<<Map[ans[i]]<<endl;
    }
}
/*
5 4 4
1 2
2 3
3 4
4 5
1 2 10
2 4 11
3 4 12
3 5 13
1 3 2
1 3 1
1 4 4
1 5 3
 */
<think>嗯,用户想查找CSP考试中第4题的相关内容或答案,特别是解析和历年真题。首先,我需要确认用户具体需要什么信息。CSP认证考试的第4题通常难度较高,涉及算法和数据结构,用户可能需要详细的题解或者解题思路。 根据提供的引用内容,引用[1]提到有一份题解集合涵盖2013年12月到2023年12月的前4题,其中第四题有详细注释。引用[2]是一个目录,可能包含各次考试的2、3题解析,但不确定是否包括第4题。引用[3]则提到小熊的篮作为第4题的真题示例,可能是一个具体的题目解析。 用户可能是在备考CSP认证,尤其是针对较难的第4题,需要找到可靠的资源来练习。他们可能遇到了解题困难,或者想验证自己的答案是否正确。需要确保提供的解析是满分答案,并且有详细的思路说明,这对用户来说非常重要。 下来,我应该整理引用中的信息,指出题解集合的位置和内容,强调覆盖范围和详细程度。同时,提到具体的例子如小熊的篮题,帮助用户理解解析的结构。此外,提醒用户访问提供的链获取完整资料,并建议结合真题练习,这样能有效提升他们的解题能力。 需要注意的是,用户可能对如何获取这些资源有疑问,所以需要明确说明来源和获取方式。同时,生成的相关问题应该围绕如何高效备考、资源整合方法以及解题技巧,这些都是用户可能关心的后续问题。</think>### CSP认证第四题解析与真题资源 根据CSP认证的真题结构和引用资料,第四题通常涉及中等偏上难度的算法设计与实现,主要考察动态规划、图论、数据结构等综合能力。以下是具体解析方法和资源指引: --- #### 一、第四题题型特点 1. **算法复杂度要求高**:通常需要设计$O(n \log n)$或更优的算法,例如分治、线段树优化等[^1]。 2. **数据规模大**:输入规模常达到$10^5$级别,需注意时间限制(如1秒对应$10^8$次运算)。 3. **典型题型**:动态规划(背包问题、状态压缩)、图论(最短路径、连通性)、树结构(LCA、树形DP)等。 --- #### 二、真题解析示例:小熊的篮(CSP-J 2021年第4题) **题目要求**:处理水果篮的多次挑选操作,输出每次挑选的水果编号。 **解题思路**: 1. **数据结构选择**:使用双向链表维护水果序列,并用队列记录当前可选的块。 2. **块合并策略**:每次挑选后检查相邻块是否需要合并,时间复杂度$O(n)$[^3]。 **关键代码片段**: ```python class FruitBlock: def __init__(self, start, end, type): self.start = start self.end = end self.type = type blocks = deque() # 初始化块队列... while blocks: current = blocks.popleft() # 输出当前块编号并处理相邻块合并 ``` --- #### 三、完整资源获取方式 1. **历年真题解析集合**: - 覆盖2013年12月至2023年12月**所有前四题满分题解**,第四题含详细注释 - 资源链:引用[1]中提到的[CCF CSP认证考试历年真题满分题解](需替换为实际链) 2. **按时间检索**: 引用[2]提供的目录可按认证时间(如"2020.09 第20次认证")定位对应第四题解析。 --- #### 四、备考建议 1. **重点突破方向**: - 动态规划:线性DP、状态机模型(如股票买卖问题) - 图论算法:Dijkstra、Floyd、拓扑排序 - 高级数据结构:并查集、线段树、红黑树 2. **模拟训练**:使用**CSP官方评测环境**测试代码,避免本地通过但提交超时。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值